aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--recipes-kernel/linux/files/0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch142
-rw-r--r--recipes-kernel/linux/files/0002-driver-core-constify-data-for-class_find_devic-quark.patch495
-rw-r--r--recipes-kernel/linux/files/0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch38
-rw-r--r--recipes-kernel/linux/files/0004-pwm-Add-sysfs-interface-quark.patch684
-rw-r--r--recipes-kernel/linux/files/0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch26
-rw-r--r--recipes-kernel/linux/files/0006-core-Quark-patch-quark.patch3374
-rw-r--r--recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch6501
-rw-r--r--recipes-kernel/linux/files/0008-Quark-UART-quark.patch5894
-rw-r--r--recipes-kernel/linux/files/0009-EFI-capsule-update-quark.patch398
-rw-r--r--recipes-kernel/linux/files/0010-Quark-SDIO-host-controller-quark.patch63
-rw-r--r--recipes-kernel/linux/files/0011-Quark-USB-host-quark.patch95
-rw-r--r--recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch348
-rw-r--r--recipes-kernel/linux/files/0013-Quark-stmmac-Ethernet-quark.patch2219
-rw-r--r--recipes-kernel/linux/files/0014-Quark-GPIO-2-2-quark.patch922
-rw-r--r--recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch272
-rw-r--r--recipes-kernel/linux/files/0016-Quark-GIP-Cypress-I-O-expander-quark.patch3822
-rw-r--r--recipes-kernel/linux/files/0017-Quark-I2C-quark.patch417
-rw-r--r--recipes-kernel/linux/files/0018-Quark-sensors-quark.patch2155
-rw-r--r--recipes-kernel/linux/files/0019-Quark-SC-SPI-quark.patch2349
-rw-r--r--recipes-kernel/linux/files/0020-Quark-IIO-quark.patch2742
-rw-r--r--recipes-kernel/linux/files/0021-Quark-SPI-flash-quark.patch41
-rw-r--r--recipes-kernel/linux/files/clanton-standard.scc2
-rw-r--r--recipes-kernel/linux/files/clanton.patch33493
-rw-r--r--recipes-kernel/linux/files/quark.cfg (renamed from recipes-kernel/linux/files/clanton.cfg)39
-rw-r--r--recipes-kernel/linux/linux-yocto-clanton_3.8.bb28
25 files changed, 33038 insertions, 33521 deletions
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
new file mode 100644
index 0000000..4d0fd37
--- /dev/null
+++ b/recipes-kernel/linux/files/0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch
@@ -0,0 +1,142 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Tue, 25 Dec 2012 23:02:48 +0100
+Subject: [PATCH 01/21] tty: don't deadlock while flushing workqueue
+
+Since commit 89c8d91e31f2 ("tty: localise the lock") I see a dead lock
+in one of my dummy_hcd + g_nokia test cases. The first run was usually
+okay, the second often resulted in a splat by lockdep and the third was
+usually a dead lock.
+Lockdep complained about tty->hangup_work and tty->legacy_mutex taken
+both ways:
+| ======================================================
+| [ INFO: possible circular locking dependency detected ]
+| 3.7.0-rc6+ #204 Not tainted
+| -------------------------------------------------------
+| kworker/2:1/35 is trying to acquire lock:
+| (&tty->legacy_mutex){+.+.+.}, at: [<c14051e6>] tty_lock_nested+0x36/0x80
+|
+| but task is already holding lock:
+| ((&tty->hangup_work)){+.+...}, at: [<c104f6e4>] process_one_work+0x124/0x5e0
+|
+| which lock already depends on the new lock.
+|
+| the existing dependency chain (in reverse order) is:
+|
+| -> #2 ((&tty->hangup_work)){+.+...}:
+| [<c107fe74>] lock_acquire+0x84/0x190
+| [<c104d82d>] flush_work+0x3d/0x240
+| [<c12e6986>] tty_ldisc_flush_works+0x16/0x30
+| [<c12e7861>] tty_ldisc_release+0x21/0x70
+| [<c12e0dfc>] tty_release+0x35c/0x470
+| [<c1105e28>] __fput+0xd8/0x270
+| [<c1105fcd>] ____fput+0xd/0x10
+| [<c1051dd9>] task_work_run+0xb9/0xf0
+| [<c1002a51>] do_notify_resume+0x51/0x80
+| [<c140550a>] work_notifysig+0x35/0x3b
+|
+| -> #1 (&tty->legacy_mutex/1){+.+...}:
+| [<c107fe74>] lock_acquire+0x84/0x190
+| [<c140276c>] mutex_lock_nested+0x6c/0x2f0
+| [<c14051e6>] tty_lock_nested+0x36/0x80
+| [<c1405279>] tty_lock_pair+0x29/0x70
+| [<c12e0bb8>] tty_release+0x118/0x470
+| [<c1105e28>] __fput+0xd8/0x270
+| [<c1105fcd>] ____fput+0xd/0x10
+| [<c1051dd9>] task_work_run+0xb9/0xf0
+| [<c1002a51>] do_notify_resume+0x51/0x80
+| [<c140550a>] work_notifysig+0x35/0x3b
+|
+| -> #0 (&tty->legacy_mutex){+.+.+.}:
+| [<c107f3c9>] __lock_acquire+0x1189/0x16a0
+| [<c107fe74>] lock_acquire+0x84/0x190
+| [<c140276c>] mutex_lock_nested+0x6c/0x2f0
+| [<c14051e6>] tty_lock_nested+0x36/0x80
+| [<c140523f>] tty_lock+0xf/0x20
+| [<c12df8e4>] __tty_hangup+0x54/0x410
+| [<c12dfcb2>] do_tty_hangup+0x12/0x20
+| [<c104f763>] process_one_work+0x1a3/0x5e0
+| [<c104fec9>] worker_thread+0x119/0x3a0
+| [<c1055084>] kthread+0x94/0xa0
+| [<c140ca37>] ret_from_kernel_thread+0x1b/0x28
+|
+|other info that might help us debug this:
+|
+|Chain exists of:
+| &tty->legacy_mutex --> &tty->legacy_mutex/1 --> (&tty->hangup_work)
+|
+| Possible unsafe locking scenario:
+|
+| CPU0 CPU1
+| ---- ----
+| lock((&tty->hangup_work));
+| lock(&tty->legacy_mutex/1);
+| lock((&tty->hangup_work));
+| lock(&tty->legacy_mutex);
+|
+| *** DEADLOCK ***
+
+Before the path mentioned tty_ldisc_release() look like this:
+
+| tty_ldisc_halt(tty);
+| tty_ldisc_flush_works(tty);
+| tty_lock();
+
+As it can be seen, it first flushes the workqueue and then grabs the
+tty_lock. Now we grab the lock first:
+
+| tty_lock_pair(tty, o_tty);
+| tty_ldisc_halt(tty);
+| tty_ldisc_flush_works(tty);
+
+so lockdep's complaint seems valid.
+
+The earlier version of this patch took the ldisc_mutex since the other
+user of tty_ldisc_flush_works() (tty_set_ldisc()) did this.
+Peter Hurley then said that it is should not be requried. Since it
+wasn't done earlier, I dropped this part.
+The code under tty_ldisc_kill() was executed earlier with the tty lock
+taken so it is taken again.
+
+I was able to reproduce the deadlock on v3.8-rc1, this patch fixes the
+problem in my testcase. I didn't notice any problems so far.
+
+Cc: Alan Cox <alan@linux.intel.com>
+Cc: Peter Hurley <peter@hurleysoftware.com>
+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(-)
+
+diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
+index c578229..78f1be2 100644
+--- a/drivers/tty/tty_ldisc.c
++++ b/drivers/tty/tty_ldisc.c
+@@ -934,17 +934,17 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
+ * race with the set_ldisc code path.
+ */
+
+- tty_lock_pair(tty, o_tty);
+ tty_ldisc_halt(tty);
+- tty_ldisc_flush_works(tty);
+- if (o_tty) {
++ if (o_tty)
+ tty_ldisc_halt(o_tty);
++
++ tty_ldisc_flush_works(tty);
++ if (o_tty)
+ tty_ldisc_flush_works(o_tty);
+- }
+
++ tty_lock_pair(tty, o_tty);
+ /* This will need doing differently if we need to lock */
+ tty_ldisc_kill(tty);
+-
+ 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
new file mode 100644
index 0000000..bf633cd
--- /dev/null
+++ b/recipes-kernel/linux/files/0002-driver-core-constify-data-for-class_find_devic-quark.patch
@@ -0,0 +1,495 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= <mirq-linux@rere.qmqm.pl>
+Date: Fri, 1 Feb 2013 20:40:17 +0100
+Subject: [PATCH 02/21] driver-core: constify data for class_find_device()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+All in-kernel users of class_find_device() don't really need mutable
+data for match callback.
+
+In two places (kernel/power/suspend_test.c, drivers/scsi/osd/osd_uld.c)
+this patch changes match callbacks to use const search data.
+
+The const is propagated to rtc_class_open() and power_supply_get_by_name()
+parameters.
+
+Note that there's a dev reference leak in suspend_test.c that's not
+touched in this patch.
+
+Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
+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 ++--
+ 19 files changed, 53 insertions(+), 64 deletions(-)
+
+diff --git a/drivers/base/class.c b/drivers/base/class.c
+index 03243d4..3ce8454 100644
+--- a/drivers/base/class.c
++++ b/drivers/base/class.c
+@@ -420,8 +420,8 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
+ * code. There's no locking restriction.
+ */
+ struct device *class_find_device(struct class *class, struct device *start,
+- void *data,
+- int (*match)(struct device *, void *))
++ const void *data,
++ int (*match)(struct device *, const void *))
+ {
+ struct class_dev_iter iter;
+ struct device *dev;
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index a235085..dda0c7f 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -1617,9 +1617,9 @@ struct device *device_create(struct class *class, struct device *parent,
+ }
+ EXPORT_SYMBOL_GPL(device_create);
+
+-static int __match_devt(struct device *dev, void *data)
++static int __match_devt(struct device *dev, const void *data)
+ {
+- dev_t *devt = data;
++ const dev_t *devt = data;
+
+ return dev->devt == *devt;
+ }
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 199fca1..5359ca7 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -806,7 +806,7 @@ fail_unlock:
+ }
+ EXPORT_SYMBOL_GPL(gpio_export);
+
+-static int match_export(struct device *dev, void *data)
++static int match_export(struct device *dev, const void *data)
+ {
+ return dev_get_drvdata(dev) == data;
+ }
+diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
+index 3e24571..da30c5c 100644
+--- a/drivers/isdn/mISDN/core.c
++++ b/drivers/isdn/mISDN/core.c
+@@ -168,13 +168,13 @@ static struct class mISDN_class = {
+ };
+
+ static int
+-_get_mdevice(struct device *dev, void *id)
++_get_mdevice(struct device *dev, const void *id)
+ {
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return 0;
+- if (mdev->id != *(u_int *)id)
++ if (mdev->id != *(const u_int *)id)
+ return 0;
+ return 1;
+ }
+diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
+index 044b532..dc92097 100644
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -95,7 +95,7 @@ static struct class mdio_bus_class = {
+
+ #if IS_ENABLED(CONFIG_OF_MDIO)
+ /* Helper function for of_mdio_find_bus */
+-static int of_mdio_bus_match(struct device *dev, void *mdio_bus_np)
++static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np)
+ {
+ return dev->of_node == mdio_bus_np;
+ }
+diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
+index 8a7cfb3..5deac43 100644
+--- a/drivers/power/power_supply_core.c
++++ b/drivers/power/power_supply_core.c
+@@ -141,7 +141,7 @@ int power_supply_set_battery_charged(struct power_supply *psy)
+ }
+ EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
+
+-static int power_supply_match_device_by_name(struct device *dev, void *data)
++static int power_supply_match_device_by_name(struct device *dev, const void *data)
+ {
+ const char *name = data;
+ struct power_supply *psy = dev_get_drvdata(dev);
+@@ -149,7 +149,7 @@ static int power_supply_match_device_by_name(struct device *dev, void *data)
+ return strcmp(psy->name, name) == 0;
+ }
+
+-struct power_supply *power_supply_get_by_name(char *name)
++struct power_supply *power_supply_get_by_name(const char *name)
+ {
+ struct device *dev = class_find_device(power_supply_class, NULL, name,
+ power_supply_match_device_by_name);
+diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
+index 9592b93..42bd57d 100644
+--- a/drivers/rtc/interface.c
++++ b/drivers/rtc/interface.c
+@@ -587,16 +587,16 @@ void rtc_update_irq(struct rtc_device *rtc,
+ }
+ EXPORT_SYMBOL_GPL(rtc_update_irq);
+
+-static int __rtc_match(struct device *dev, void *data)
++static int __rtc_match(struct device *dev, const void *data)
+ {
+- char *name = (char *)data;
++ const char *name = data;
+
+ if (strcmp(dev_name(dev), name) == 0)
+ return 1;
+ return 0;
+ }
+
+-struct rtc_device *rtc_class_open(char *name)
++struct rtc_device *rtc_class_open(const char *name)
+ {
+ struct device *dev;
+ struct rtc_device *rtc = NULL;
+diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
+index 593085a..df0c3c7 100644
+--- a/drivers/scsi/hosts.c
++++ b/drivers/scsi/hosts.c
+@@ -468,10 +468,10 @@ void scsi_unregister(struct Scsi_Host *shost)
+ }
+ EXPORT_SYMBOL(scsi_unregister);
+
+-static int __scsi_host_match(struct device *dev, void *data)
++static int __scsi_host_match(struct device *dev, const void *data)
+ {
+ struct Scsi_Host *p;
+- unsigned short *hostnum = (unsigned short *)data;
++ const unsigned short *hostnum = data;
+
+ p = class_to_shost(dev);
+ return p->host_no == *hostnum;
+diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
+index 4375417..0fab6b5 100644
+--- a/drivers/scsi/osd/osd_uld.c
++++ b/drivers/scsi/osd/osd_uld.c
+@@ -268,18 +268,11 @@ static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
+ return 0 == memcmp(a1, a2, a1_len);
+ }
+
+-struct find_oud_t {
+- const struct osd_dev_info *odi;
+- struct device *dev;
+- struct osd_uld_device *oud;
+-} ;
+-
+-int _mach_odi(struct device *dev, void *find_data)
++static int _match_odi(struct device *dev, const void *find_data)
+ {
+ struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
+ class_dev);
+- struct find_oud_t *fot = find_data;
+- const struct osd_dev_info *odi = fot->odi;
++ const struct osd_dev_info *odi = find_data;
+
+ if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
+ odi->systemid, odi->systemid_len) &&
+@@ -287,7 +280,6 @@ int _mach_odi(struct device *dev, void *find_data)
+ odi->osdname, odi->osdname_len)) {
+ OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
+ odi->systemid_len, odi->osdname_len);
+- fot->oud = oud;
+ return 1;
+ } else {
+ return 0;
+@@ -301,19 +293,19 @@ int _mach_odi(struct device *dev, void *find_data)
+ */
+ struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
+ {
+- struct find_oud_t find = {.odi = odi};
+-
+- find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
+- if (likely(find.dev)) {
++ struct device *dev = class_find_device(&osd_uld_class, NULL, odi, _match_odi);
++ if (likely(dev)) {
+ struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
++ struct osd_uld_device *oud = container_of(dev,
++ struct osd_uld_device, class_dev);
+
+ if (unlikely(!odh)) {
+- put_device(find.dev);
++ put_device(dev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+- odh->od = find.oud->od;
+- odh->oud = find.oud;
++ odh->od = oud->od;
++ odh->oud = oud;
+
+ return &odh->od;
+ }
+diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
+index 31969f2..59d427b 100644
+--- a/drivers/scsi/scsi_transport_iscsi.c
++++ b/drivers/scsi/scsi_transport_iscsi.c
+@@ -183,10 +183,10 @@ static struct attribute_group iscsi_endpoint_group = {
+
+ #define ISCSI_MAX_EPID -1
+
+-static int iscsi_match_epid(struct device *dev, void *data)
++static int iscsi_match_epid(struct device *dev, const void *data)
+ {
+ struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+- uint64_t *epid = (uint64_t *) data;
++ const uint64_t *epid = data;
+
+ return *epid == ep->id;
+ }
+diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
+index 19ee901..493ce4a 100644
+--- a/drivers/spi/spi.c
++++ b/drivers/spi/spi.c
+@@ -1248,10 +1248,10 @@ int spi_master_resume(struct spi_master *master)
+ }
+ EXPORT_SYMBOL_GPL(spi_master_resume);
+
+-static int __spi_master_match(struct device *dev, void *data)
++static int __spi_master_match(struct device *dev, const void *data)
+ {
+ struct spi_master *m;
+- u16 *bus_num = data;
++ const u16 *bus_num = data;
+
+ m = container_of(dev, struct spi_master, dev);
+ return m->bus_num == *bus_num;
+diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
+index 4d688c7..3eca6ce 100644
+--- a/drivers/uwb/lc-rc.c
++++ b/drivers/uwb/lc-rc.c
+@@ -40,9 +40,9 @@
+
+ #include "uwb-internal.h"
+
+-static int uwb_rc_index_match(struct device *dev, void *data)
++static int uwb_rc_index_match(struct device *dev, const void *data)
+ {
+- int *index = data;
++ const int *index = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc->index == *index)
+@@ -334,9 +334,9 @@ void uwb_rc_rm(struct uwb_rc *rc)
+ }
+ EXPORT_SYMBOL_GPL(uwb_rc_rm);
+
+-static int find_rc_try_get(struct device *dev, void *data)
++static int find_rc_try_get(struct device *dev, const void *data)
+ {
+- struct uwb_rc *target_rc = data;
++ const struct uwb_rc *target_rc = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+@@ -386,9 +386,9 @@ static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
+ return rc;
+ }
+
+-static int find_rc_grandpa(struct device *dev, void *data)
++static int find_rc_grandpa(struct device *dev, const void *data)
+ {
+- struct device *grandpa_dev = data;
++ const struct device *grandpa_dev = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
+@@ -419,7 +419,7 @@ struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+- dev = class_find_device(&uwb_rc_class, NULL, (void *)grandpa_dev,
++ dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
+ find_rc_grandpa);
+ if (dev)
+ rc = dev_get_drvdata(dev);
+@@ -432,9 +432,9 @@ EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
+ *
+ * @returns the pointer to the radio controller, properly referenced
+ */
+-static int find_rc_dev(struct device *dev, void *data)
++static int find_rc_dev(struct device *dev, const void *data)
+ {
+- struct uwb_dev_addr *addr = data;
++ const struct uwb_dev_addr *addr = data;
+ struct uwb_rc *rc = dev_get_drvdata(dev);
+
+ if (rc == NULL) {
+@@ -453,8 +453,7 @@ struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
+ struct device *dev;
+ struct uwb_rc *rc = NULL;
+
+- dev = class_find_device(&uwb_rc_class, NULL, (void *)addr,
+- find_rc_dev);
++ dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
+ if (dev)
+ rc = dev_get_drvdata(dev);
+
+diff --git a/include/linux/device.h b/include/linux/device.h
+index 43dcda9..13de5ee 100644
+--- a/include/linux/device.h
++++ b/include/linux/device.h
+@@ -395,8 +395,8 @@ extern int class_for_each_device(struct class *class, struct device *start,
+ void *data,
+ int (*fn)(struct device *dev, void *data));
+ extern struct device *class_find_device(struct class *class,
+- struct device *start, void *data,
+- int (*match)(struct device *, void *));
++ struct device *start, const void *data,
++ int (*match)(struct device *, const void *));
+
+ struct class_attribute {
+ struct attribute attr;
+diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
+index 1f0ab90..86ecaa6 100644
+--- a/include/linux/power_supply.h
++++ b/include/linux/power_supply.h
+@@ -224,7 +224,7 @@ struct power_supply_info {
+ int use_for_apm;
+ };
+
+-extern struct power_supply *power_supply_get_by_name(char *name);
++extern struct power_supply *power_supply_get_by_name(const char *name);
+ extern void power_supply_changed(struct power_supply *psy);
+ extern int power_supply_am_i_supplied(struct power_supply *psy);
+ extern int power_supply_set_battery_charged(struct power_supply *psy);
+diff --git a/include/linux/rtc.h b/include/linux/rtc.h
+index 9531845c..445fe6e 100644
+--- a/include/linux/rtc.h
++++ b/include/linux/rtc.h
+@@ -148,7 +148,7 @@ extern int rtc_initialize_alarm(struct rtc_device *rtc,
+ extern void rtc_update_irq(struct rtc_device *rtc,
+ unsigned long num, unsigned long events);
+
+-extern struct rtc_device *rtc_class_open(char *name);
++extern struct rtc_device *rtc_class_open(const char *name);
+ extern void rtc_class_close(struct rtc_device *rtc);
+
+ extern int rtc_irq_register(struct rtc_device *rtc,
+diff --git a/init/do_mounts.c b/init/do_mounts.c
+index 1d1b634..a2b49f2 100644
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -81,9 +81,9 @@ struct uuidcmp {
+ *
+ * Returns 1 if the device matches, and 0 otherwise.
+ */
+-static int match_dev_by_uuid(struct device *dev, void *data)
++static int match_dev_by_uuid(struct device *dev, const void *data)
+ {
+- struct uuidcmp *cmp = data;
++ const struct uuidcmp *cmp = data;
+ struct hd_struct *part = dev_to_part(dev);
+
+ if (!part->info)
+diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c
+index 25596e4..9b2a1d5 100644
+--- a/kernel/power/suspend_test.c
++++ b/kernel/power/suspend_test.c
+@@ -112,7 +112,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
+ rtc_set_alarm(rtc, &alm);
+ }
+
+-static int __init has_wakealarm(struct device *dev, void *name_ptr)
++static int __init has_wakealarm(struct device *dev, const void *data)
+ {
+ struct rtc_device *candidate = to_rtc_device(dev);
+
+@@ -121,7 +121,6 @@ static int __init has_wakealarm(struct device *dev, void *name_ptr)
+ if (!device_may_wakeup(candidate->dev.parent))
+ return 0;
+
+- *(const char **)name_ptr = dev_name(dev);
+ return 1;
+ }
+
+@@ -159,8 +158,8 @@ static int __init test_suspend(void)
+ static char warn_no_rtc[] __initdata =
+ KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
+
+- char *pony = NULL;
+ struct rtc_device *rtc = NULL;
++ struct device *dev;
+
+ /* PM is initialized by now; is that state testable? */
+ if (test_state == PM_SUSPEND_ON)
+@@ -171,9 +170,9 @@ static int __init test_suspend(void)
+ }
+
+ /* RTCs have initialized by now too ... can we use one? */
+- class_find_device(rtc_class, NULL, &pony, has_wakealarm);
+- if (pony)
+- rtc = rtc_class_open(pony);
++ dev = class_find_device(rtc_class, NULL, NULL, has_wakealarm);
++ if (dev)
++ rtc = rtc_class_open(dev_name(dev));
+ if (!rtc) {
+ printk(warn_no_rtc);
+ goto done;
+diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c
+index 1627ef2..13571ea 100644
+--- a/net/ieee802154/wpan-class.c
++++ b/net/ieee802154/wpan-class.c
+@@ -91,7 +91,7 @@ static struct class wpan_phy_class = {
+ static DEFINE_MUTEX(wpan_phy_mutex);
+ static int wpan_phy_idx;
+
+-static int wpan_phy_match(struct device *dev, void *data)
++static int wpan_phy_match(struct device *dev, const void *data)
+ {
+ return !strcmp(dev_name(dev), (const char *)data);
+ }
+@@ -103,8 +103,7 @@ struct wpan_phy *wpan_phy_find(const char *str)
+ if (WARN_ON(!str))
+ return NULL;
+
+- dev = class_find_device(&wpan_phy_class, NULL,
+- (void *)str, wpan_phy_match);
++ dev = class_find_device(&wpan_phy_class, NULL, str, wpan_phy_match);
+ if (!dev)
+ return NULL;
+
+diff --git a/net/nfc/core.c b/net/nfc/core.c
+index aa64ea4..0f4a6de 100644
+--- a/net/nfc/core.c
++++ b/net/nfc/core.c
+@@ -734,10 +734,10 @@ struct class nfc_class = {
+ };
+ EXPORT_SYMBOL(nfc_class);
+
+-static int match_idx(struct device *d, void *data)
++static int match_idx(struct device *d, const void *data)
+ {
+ struct nfc_dev *dev = to_nfc_dev(d);
+- unsigned int *idx = data;
++ const unsigned int *idx = data;
+
+ 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
new file mode 100644
index 0000000..ab3eb1e
--- /dev/null
+++ b/recipes-kernel/linux/files/0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch
@@ -0,0 +1,38 @@
+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
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Michał's previous patch missed this tty check to fix up the
+class_find_device() arguments.
+
+Reported-by: kbuild test robot <fengguang.wu@intel.com>
+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(-)
+
+diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
+index da9fde8..6b20fd6 100644
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -2906,9 +2906,9 @@ void do_SAK(struct tty_struct *tty)
+
+ EXPORT_SYMBOL(do_SAK);
+
+-static int dev_match_devt(struct device *dev, void *data)
++static int dev_match_devt(struct device *dev, const void *data)
+ {
+- dev_t *devt = data;
++ const dev_t *devt = data;
+ 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
new file mode 100644
index 0000000..fb4ee30
--- /dev/null
+++ b/recipes-kernel/linux/files/0004-pwm-Add-sysfs-interface-quark.patch
@@ -0,0 +1,684 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: H Hartley Sweeten <hartleys@visionengravers.com>
+Date: Tue, 11 Jun 2013 10:38:59 -0700
+Subject: [PATCH 04/21] pwm: Add sysfs interface
+
+Add a simple sysfs interface to the generic PWM framework.
+
+ /sys/class/pwm/
+ `-- pwmchipN/ for each PWM chip
+ |-- export (w/o) ask the kernel to export a PWM channel
+ |-- npwm (r/o) number of PWM channels in this PWM chip
+ |-- pwmX/ for each exported PWM channel
+ | |-- duty_cycle (r/w) duty cycle (in nanoseconds)
+ | |-- enable (r/w) enable/disable PWM
+ | |-- period (r/w) period (in nanoseconds)
+ | `-- polarity (r/w) polarity of PWM (normal/inversed)
+ `-- unexport (w/o) return a PWM channel to the kernel
+
+Based on work by Lars Poeschel.
+
+Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Lars Poeschel <poeschel@lemonage.de>
+Cc: Ryan Mallon <rmallon@gmail.com>
+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 +++-
+ 7 files changed, 524 insertions(+), 3 deletions(-)
+ create mode 100644 Documentation/ABI/testing/sysfs-class-pwm
+ create mode 100644 drivers/pwm/sysfs.c
+
+diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm
+new file mode 100644
+index 0000000..c479d77
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-pwm
+@@ -0,0 +1,79 @@
++What: /sys/class/pwm/
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ The pwm/ class sub-directory belongs to the Generic PWM
++ Framework and provides a sysfs interface for using PWM
++ channels.
++
++What: /sys/class/pwm/pwmchipN/
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ A /sys/class/pwm/pwmchipN directory is created for each
++ probed PWM controller/chip where N is the base of the
++ PWM chip.
++
++What: /sys/class/pwm/pwmchipN/npwm
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ The number of PWM channels supported by the PWM chip.
++
++What: /sys/class/pwm/pwmchipN/export
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Exports a PWM channel from the PWM chip for sysfs control.
++ Value is between 0 and /sys/class/pwm/pwmchipN/npwm - 1.
++
++What: /sys/class/pwm/pwmchipN/unexport
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Unexports a PWM channel.
++
++What: /sys/class/pwm/pwmchipN/pwmX
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ A /sys/class/pwm/pwmchipN/pwmX directory is created for
++ each exported PWM channel where X is the exported PWM
++ channel number.
++
++What: /sys/class/pwm/pwmchipN/pwmX/period
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Sets the PWM signal period in nanoseconds.
++
++What: /sys/class/pwm/pwmchipN/pwmX/duty_cycle
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Sets the PWM signal duty cycle in nanoseconds.
++
++What: /sys/class/pwm/pwmchipN/pwmX/polarity
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Sets the output polarity of the PWM signal to "normal" or
++ "inversed".
++
++What: /sys/class/pwm/pwmchipN/pwmX/enable
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Enable/disable the PWM signal.
++ 0 is disabled
++ 1 is enabled
+diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
+index 7d2b4c9..1039b68 100644
+--- a/Documentation/pwm.txt
++++ b/Documentation/pwm.txt
+@@ -45,6 +45,43 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
+
+ To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
+
++Using PWMs with the sysfs interface
++-----------------------------------
++
++If CONFIG_SYSFS is enabled in your kernel configuration a simple sysfs
++interface is provided to use the PWMs from userspace. It is exposed at
++/sys/class/pwm/. Each probed PWM controller/chip will be exported as
++pwmchipN, where N is the base of the PWM chip. Inside the directory you
++will find:
++
++npwm - The number of PWM channels this chip supports (read-only).
++
++export - Exports a PWM channel for use with sysfs (write-only).
++
++unexport - Unexports a PWM channel from sysfs (write-only).
++
++The PWM channels are numbered using a per-chip index from 0 to npwm-1.
++
++When a PWM channel is exported a pwmX directory will be created in the
++pwmchipN directory it is associated with, where X is the number of the
++channel that was exported. The following properties will then be available:
++
++period - The total period of the PWM signal (read/write).
++ Value is in nanoseconds and is the sum of the active and inactive
++ time of the PWM.
++
++duty_cycle - The active time of the PWM signal (read/write).
++ Value is in nanoseconds and must be less than the period.
++
++polarity - Changes the polarity of the PWM signal (read/write).
++ Writes to this property only work if the PWM chip supports changing
++ the polarity. The polarity can only be changed if the PWM is not
++ enabled. Value is the string "normal" or "inversed".
++
++enable - Enable/disable the PWM signal (read/write).
++ 0 - disabled
++ 1 - enabled
++
+ Implementing a PWM driver
+ -------------------------
+
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index e513cd9..03120a8 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -28,6 +28,10 @@ menuconfig PWM
+
+ if PWM
+
++config PWM_SYSFS
++ bool
++ default y if SYSFS
++
+ config PWM_AB8500
+ tristate "AB8500 PWM support"
+ depends on AB8500_CORE && ARCH_U8500
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index 62a2963..f98371b 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -1,4 +1,5 @@
+ obj-$(CONFIG_PWM) += core.o
++obj-$(CONFIG_PWM_SYSFS) += sysfs.o
+ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
+ obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
+ obj-$(CONFIG_PWM_IMX) += pwm-imx.o
+diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
+index 903138b..bfc8c05 100644
+--- a/drivers/pwm/core.c
++++ b/drivers/pwm/core.c
+@@ -272,6 +272,8 @@ int pwmchip_add(struct pwm_chip *chip)
+ if (IS_ENABLED(CONFIG_OF))
+ of_pwmchip_add(chip);
+
++ pwmchip_sysfs_export(chip);
++
+ out:
+ mutex_unlock(&pwm_lock);
+ return ret;
+@@ -308,6 +310,8 @@ int pwmchip_remove(struct pwm_chip *chip)
+
+ free_pwms(chip);
+
++ pwmchip_sysfs_unexport(chip);
++
+ out:
+ mutex_unlock(&pwm_lock);
+ return ret;
+@@ -400,10 +404,19 @@ EXPORT_SYMBOL_GPL(pwm_free);
+ */
+ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+ {
++ int err;
++
+ if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+- return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
++ err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
++ if (err)
++ return err;
++
++ pwm->duty_cycle = duty_ns;
++ pwm->period = period_ns;
++
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(pwm_config);
+
+@@ -416,6 +429,8 @@ EXPORT_SYMBOL_GPL(pwm_config);
+ */
+ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+ {
++ int err;
++
+ if (!pwm || !pwm->chip->ops)
+ return -EINVAL;
+
+@@ -425,7 +440,13 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+ if (test_bit(PWMF_ENABLED, &pwm->flags))
+ return -EBUSY;
+
+- return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
++ err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
++ if (err)
++ return err;
++
++ pwm->polarity = polarity;
++
++ return 0;
+ }
+ EXPORT_SYMBOL_GPL(pwm_set_polarity);
+
+diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
+new file mode 100644
+index 0000000..8ca5de3
+--- /dev/null
++++ b/drivers/pwm/sysfs.c
+@@ -0,0 +1,352 @@
++/*
++ * A simple sysfs interface for the generic PWM framework
++ *
++ * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com>
++ *
++ * Based on previous work by Lars Poeschel <poeschel@lemonage.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/device.h>
++#include <linux/mutex.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/kdev_t.h>
++#include <linux/pwm.h>
++
++struct pwm_export {
++ struct device child;
++ struct pwm_device *pwm;
++};
++
++static struct pwm_export *child_to_pwm_export(struct device *child)
++{
++ return container_of(child, struct pwm_export, child);
++}
++
++static struct pwm_device *child_to_pwm_device(struct device *child)
++{
++ struct pwm_export *export = child_to_pwm_export(child);
++
++ return export->pwm;
++}
++
++static ssize_t pwm_period_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++
++ return sprintf(buf, "%u\n", pwm->period);
++}
++
++static ssize_t pwm_period_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ unsigned int val;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ ret = pwm_config(pwm, pwm->duty_cycle, val);
++
++ return ret ? : size;
++}
++
++static ssize_t pwm_duty_cycle_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++
++ return sprintf(buf, "%u\n", pwm->duty_cycle);
++}
++
++static ssize_t pwm_duty_cycle_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ unsigned int val;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ ret = pwm_config(pwm, val, pwm->period);
++
++ return ret ? : size;
++}
++
++static ssize_t pwm_enable_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++ int enabled = test_bit(PWMF_ENABLED, &pwm->flags);
++
++ return sprintf(buf, "%d\n", enabled);
++}
++
++static ssize_t pwm_enable_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ int val, ret;
++
++ ret = kstrtoint(buf, 0, &val);
++ if (ret)
++ return ret;
++
++ switch (val) {
++ case 0:
++ pwm_disable(pwm);
++ break;
++ case 1:
++ ret = pwm_enable(pwm);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ return ret ? : size;
++}
++
++static ssize_t pwm_polarity_show(struct device *child,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_device *pwm = child_to_pwm_device(child);
++
++ return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal");
++}
++
++static ssize_t pwm_polarity_store(struct device *child,
++ struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct pwm_device *pwm = child_to_pwm_device(child);
++ enum pwm_polarity polarity;
++ int ret;
++
++ if (sysfs_streq(buf, "normal"))
++ polarity = PWM_POLARITY_NORMAL;
++ else if (sysfs_streq(buf, "inversed"))
++ polarity = PWM_POLARITY_INVERSED;
++ else
++ return -EINVAL;
++
++ ret = pwm_set_polarity(pwm, polarity);
++
++ return ret ? : size;
++}
++
++static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store);
++static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store);
++static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store);
++static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store);
++
++static struct attribute *pwm_attrs[] = {
++ &dev_attr_period.attr,
++ &dev_attr_duty_cycle.attr,
++ &dev_attr_enable.attr,
++ &dev_attr_polarity.attr,
++ NULL
++};
++
++static const struct attribute_group pwm_attr_group = {
++ .attrs = pwm_attrs,
++};
++
++static const struct attribute_group *pwm_attr_groups[] = {
++ &pwm_attr_group,
++ NULL,
++};
++
++static void pwm_export_release(struct device *child)
++{
++ struct pwm_export *export = child_to_pwm_export(child);
++
++ kfree(export);
++}
++
++static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
++{
++ struct pwm_export *export;
++ int ret;
++
++ if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
++ return -EBUSY;
++
++ export = kzalloc(sizeof(*export), GFP_KERNEL);
++ if (!export) {
++ clear_bit(PWMF_EXPORTED, &pwm->flags);
++ return -ENOMEM;
++ }
++
++ export->pwm = pwm;
++
++ export->child.release = pwm_export_release;
++ export->child.parent = parent;
++ export->child.devt = MKDEV(0, 0);
++ export->child.groups = pwm_attr_groups;
++ dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
++
++ ret = device_register(&export->child);
++ if (ret) {
++ clear_bit(PWMF_EXPORTED, &pwm->flags);
++ kfree(export);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int pwm_unexport_match(struct device *child, void *data)
++{
++ return child_to_pwm_device(child) == data;
++}
++
++static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
++{
++ struct device *child;
++
++ if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
++ return -ENODEV;
++
++ child = device_find_child(parent, pwm, pwm_unexport_match);
++ if (!child)
++ return -ENODEV;
++
++ /* for device_find_child() */
++ put_device(child);
++ device_unregister(child);
++ pwm_put(pwm);
++
++ return 0;
++}
++
++static ssize_t pwm_export_store(struct device *parent,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct pwm_chip *chip = dev_get_drvdata(parent);
++ struct pwm_device *pwm;
++ unsigned int hwpwm;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &hwpwm);
++ if (ret < 0)
++ return ret;
++
++ if (hwpwm >= chip->npwm)
++ return -ENODEV;
++
++ pwm = pwm_request_from_chip(chip, hwpwm, "sysfs");
++ if (IS_ERR(pwm))
++ return PTR_ERR(pwm);
++
++ ret = pwm_export_child(parent, pwm);
++ if (ret < 0)
++ pwm_put(pwm);
++
++ return ret ? : len;
++}
++
++static ssize_t pwm_unexport_store(struct device *parent,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct pwm_chip *chip = dev_get_drvdata(parent);
++ unsigned int hwpwm;
++ int ret;
++
++ ret = kstrtouint(buf, 0, &hwpwm);
++ if (ret < 0)
++ return ret;
++
++ if (hwpwm >= chip->npwm)
++ return -ENODEV;
++
++ ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]);
++
++ return ret ? : len;
++}
++
++static ssize_t pwm_npwm_show(struct device *parent,
++ struct device_attribute *attr,
++ char *buf)
++{
++ const struct pwm_chip *chip = dev_get_drvdata(parent);
++
++ return sprintf(buf, "%u\n", chip->npwm);
++}
++
++static struct device_attribute pwm_chip_attrs[] = {
++ __ATTR(export, 0200, NULL, pwm_export_store),
++ __ATTR(unexport, 0200, NULL, pwm_unexport_store),
++ __ATTR(npwm, 0444, pwm_npwm_show, NULL),
++ __ATTR_NULL,
++};
++
++static struct class pwm_class = {
++ .name = "pwm",
++ .owner = THIS_MODULE,
++ .dev_attrs = pwm_chip_attrs,
++};
++
++static int pwmchip_sysfs_match(struct device *parent, const void *data)
++{
++ return dev_get_drvdata(parent) == data;
++}
++
++void pwmchip_sysfs_export(struct pwm_chip *chip)
++{
++ struct device *parent;
++
++ /*
++ * If device_create() fails the pwm_chip is still usable by
++ * the kernel its just not exported.
++ */
++ parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
++ "pwmchip%d", chip->base);
++ if (IS_ERR(parent)) {
++ dev_warn(chip->dev,
++ "device_create failed for pwm_chip sysfs export\n");
++ }
++}
++
++void pwmchip_sysfs_unexport(struct pwm_chip *chip)
++{
++ struct device *parent;
++
++ parent = class_find_device(&pwm_class, NULL, chip,
++ pwmchip_sysfs_match);
++ if (parent) {
++ /* for class_find_device() */
++ put_device(parent);
++ device_unregister(parent);
++ }
++}
++
++static int __init pwm_sysfs_init(void)
++{
++ return class_register(&pwm_class);
++}
++subsys_initcall(pwm_sysfs_init);
+diff --git a/include/linux/pwm.h b/include/linux/pwm.h
+index 6d661f3..6842d11 100644
+--- a/include/linux/pwm.h
++++ b/include/linux/pwm.h
+@@ -76,6 +76,7 @@ enum pwm_polarity {
+ enum {
+ PWMF_REQUESTED = 1 << 0,
+ PWMF_ENABLED = 1 << 1,
++ PWMF_EXPORTED = 1 << 2,
+ };
+
+ struct pwm_device {
+@@ -86,7 +87,9 @@ struct pwm_device {
+ struct pwm_chip *chip;
+ void *chip_data;
+
+- unsigned int period; /* in nanoseconds */
++ unsigned int period; /* in nanoseconds */
++ unsigned int duty_cycle; /* in nanoseconds */
++ enum pwm_polarity polarity;
+ };
+
+ static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
+@@ -100,6 +103,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
+ return pwm ? pwm->period : 0;
+ }
+
++static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
++{
++ if (pwm)
++ pwm->duty_cycle = duty;
++}
++
++static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm)
++{
++ return pwm ? pwm->duty_cycle : 0;
++}
++
+ /*
+ * pwm_set_polarity - configure the polarity of a PWM signal
+ */
+@@ -252,4 +266,17 @@ static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
+ }
+ #endif
+
++#ifdef CONFIG_PWM_SYSFS
++void pwmchip_sysfs_export(struct pwm_chip *chip);
++void pwmchip_sysfs_unexport(struct pwm_chip *chip);
++#else
++static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
++{
++}
++
++static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
++{
++}
++#endif /* CONFIG_PWM_SYSFS */
++
+ #endif /* __LINUX_PWM_H */
+--
+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
new file mode 100644
index 0000000..3d2ade0
--- /dev/null
+++ b/recipes-kernel/linux/files/0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch
@@ -0,0 +1,26 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Josef Ahmad <josef.ahmad@linux.intel.com>
+Date: Mon, 9 Sep 2013 14:11:51 +0100
+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(-)
+
+diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
+index 8ca5de3..4cd6d78 100644
+--- a/drivers/pwm/sysfs.c
++++ b/drivers/pwm/sysfs.c
+@@ -16,6 +16,7 @@
+ * GNU General Public License for more details.
+ */
+
++#include <linux/export.h>
+ #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
new file mode 100644
index 0000000..8e2d252
--- /dev/null
+++ b/recipes-kernel/linux/files/0006-core-Quark-patch-quark.patch
@@ -0,0 +1,3374 @@
+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
+Subject: [PATCH 06/21] core Quark patch
+
+---
+ arch/x86/Kconfig | 23 +
+ arch/x86/include/asm/imr.h | 22 +
+ arch/x86/include/asm/qrk.h | 85 +
+ 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 +
+ meta/cfg/kernel-cache/bsp/quark/quark.cfg | 3044 +++++++++++++++++++++++++++++
+ 9 files changed, 3212 insertions(+), 6 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
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -417,6 +417,15 @@ config X86_INTEL_CE
+ This option compiles in support for the CE4100 SOC for settop
+ boxes and media devices.
+
++config INTEL_QUARK_X1000_SOC
++ bool "Intel Quark X1000 SOC support"
++ depends on M586TSC
++ select ARCH_REQUIRE_GPIOLIB
++ select I2C
++ ---help---
++ Quark X1000 SOC support . This option enables probing for various
++ PCI-IDs of several on-chip devices provided by the X1000
++
+ config X86_WANT_INTEL_MID
+ bool "Intel MID platform support"
+ depends on X86_32
+@@ -500,6 +509,13 @@ config X86_SUPPORTS_MEMORY_FAILURE
+ depends on X86_64 || !SPARSEMEM
+ select ARCH_SUPPORTS_MEMORY_FAILURE
+
++menu "Intel Media SOC Gen3 support"
++
++config ARCH_GEN3
++ bool "Enable Intel Media SOC Gen3 support"
++ default y
++
++endmenu
+ config X86_VISWS
+ bool "SGI 320/540 (Visual Workstation)"
+ depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT
+@@ -1524,6 +1540,13 @@ config EFI_STUB
+
+ See Documentation/x86/efi-stub.txt for more information.
+
++config EFI_CAPSULE
++ tristate "EFI capsule update support"
++ depends on EFI
++ ---help---
++ This kernel feature allows for loading of EFI capsule code
++ with callbacks into the EDK firmware to execute update
++
+ config SECCOMP
+ def_bool y
+ prompt "Enable seccomp to safely compute untrusted bytecode"
+diff --git a/arch/x86/include/asm/imr.h b/arch/x86/include/asm/imr.h
+new file mode 100644
+index 0000000..876d499
+--- /dev/null
++++ b/arch/x86/include/asm/imr.h
+@@ -0,0 +1,22 @@
++/*
++ * imr.h: Intel Quark platform imr setup code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; version 2
++ * of the License.
++ */
++#ifndef _ASM_X86_IMR_H
++#define _ASM_X86_IMR_H
++
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ extern int intel_qrk_imr_runt_setparams(void);
++ extern int intel_qrk_imr_lockall(void);
++#else
++ static void intel_qrk_imr_runt_setparams(void){}
++ static void intel_qrk_imr_lockall(void){}
++#endif
++
++#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
+--- /dev/null
++++ b/arch/x86/include/asm/qrk.h
+@@ -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 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
++ */
++#ifndef _ASM_X86_QRK_H
++#define _ASM_X86_QRK_H
++
++#include <linux/pci.h>
++#include <linux/msi.h>
++
++/**
++ * qrk_pci_pvm_mask
++ *
++ * Mask PVM bit on a per function basis. Quark SC components have but one
++ * vector each - so we mask for what we need
++ */
++static inline void qrk_pci_pvm_mask(struct pci_dev * dev)
++{
++ struct msi_desc *entry;
++ int mask_bits = 1;
++
++ if(unlikely(dev->msi_enabled == 0))
++ return;
++
++ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
++
++ if(unlikely(entry == NULL))
++ return;
++
++ pci_write_config_dword(dev, entry->mask_pos, mask_bits);
++}
++
++/**
++ * qrk_pci_pvm_mask
++ *
++ * UnMask PVM bit on a per function basis. Quark SC components have but one
++ * vector each - so we unmask for what we need
++ */
++static inline void qrk_pci_pvm_unmask(struct pci_dev * dev)
++{
++ struct msi_desc *entry;
++ int mask_bits = 0;
++
++ if(unlikely(dev->msi_enabled == 0))
++ return;
++
++ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
++
++ if(unlikely(entry == NULL))
++ return;
++
++ pci_write_config_dword(dev, entry->mask_pos, mask_bits);
++}
++
++/* Convienence macros */
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define mask_pvm(x) qrk_pci_pvm_mask(x)
++ #define unmask_pvm(x) qrk_pci_pvm_unmask(x)
++#else
++ #define mask_pvm(x)
++ #define unmask_pvm(x)
++#endif
++
++/* Serial */
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define SERIAL_PORT_DFNS
++ #define BASE_BAUD 2764800
++#endif
++
++#endif /* _ASM_X86_QRK_H */
+diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h
+index 628c801..9bcaf85 100644
+--- a/arch/x86/include/asm/serial.h
++++ b/arch/x86/include/asm/serial.h
+@@ -1,6 +1,8 @@
+ #ifndef _ASM_X86_SERIAL_H
+ #define _ASM_X86_SERIAL_H
+
++#include <asm/qrk.h>
++
+ /*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+@@ -8,7 +10,9 @@
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
++#ifndef BASE_BAUD
+ #define BASE_BAUD ( 1843200 / 16 )
++#endif
+
+ /* Standard COM flags (except for COM4, because of the 8514 problem) */
+ #ifdef CONFIG_SERIAL_DETECT_IRQ
+@@ -19,11 +23,13 @@
+ #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+ #endif
+
++#ifndef SERIAL_PORT_DFNS
+ #define SERIAL_PORT_DFNS \
+ /* UART CLK PORT IRQ FLAGS */ \
+ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
+ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
+ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
+ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
++#endif
+
+ #endif /* _ASM_X86_SERIAL_H */
+diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
+index fcaabd0..ea7624c 100644
+--- a/arch/x86/kernel/cpu/intel.c
++++ b/arch/x86/kernel/cpu/intel.c
+@@ -143,6 +143,17 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
+ setup_clear_cpu_cap(X86_FEATURE_ERMS);
+ }
+ }
++
++ /*
++ * Quark X1000 PGE is advertised but not implemented. This matters since
++ * cpu_has_pge is used to determine the type of TLB flushing to do. With
++ * PGE not actually doing what it says on the tin writes to CR4.PGE do
++ * nothing when we should be re-writing CR3 like a 486
++ */
++ if (c->x86 == 5 && c->x86_model == 9){
++ printk(KERN_INFO "Disabling PGE capability bit\n");
++ setup_clear_cpu_cap(X86_FEATURE_PGE);
++ }
+ }
+
+ #ifdef CONFIG_X86_32
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 8b24289..c963186 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -761,7 +761,10 @@ void __init setup_arch(char **cmdline_p)
+ KERNEL_PGD_PTRS);
+
+ load_cr3(swapper_pg_dir);
+- __flush_tlb_all();
++ if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_model == 9)
++ __flush_tlb();
++ else
++ __flush_tlb_all();
+ #else
+ printk(KERN_INFO "Command line: %s\n", boot_command_line);
+ #endif
+diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
+index d9c1b95..9fd5168 100644
+--- a/arch/x86/platform/efi/efi-bgrt.c
++++ b/arch/x86/platform/efi/efi-bgrt.c
+@@ -24,19 +24,29 @@ struct bmp_header {
+ u32 size;
+ } __packed;
+
+-void efi_bgrt_init(void)
++bool __init efi_bgrt_probe(void)
+ {
+ acpi_status status;
+- void __iomem *image;
+- bool ioremapped = false;
+- struct bmp_header bmp_header;
+
+ if (acpi_disabled)
+- return;
++ return false;
+
++ bgrt_tab = NULL;
+ status = acpi_get_table("BGRT", 0,
+ (struct acpi_table_header **)&bgrt_tab);
+ if (ACPI_FAILURE(status))
++ return false;
++
++ return true;
++}
++
++void __init efi_bgrt_init(void)
++{
++ void __iomem *image;
++ bool ioremapped = false;
++ struct bmp_header bmp_header;
++
++ if (acpi_disabled || bgrt_tab == NULL)
+ return;
+
+ if (bgrt_tab->header.length < sizeof(*bgrt_tab))
+diff --git a/include/linux/efi-bgrt.h b/include/linux/efi-bgrt.h
+index 051b21f..165426b 100644
+--- a/include/linux/efi-bgrt.h
++++ b/include/linux/efi-bgrt.h
+@@ -6,6 +6,7 @@
+ #include <linux/acpi.h>
+
+ void efi_bgrt_init(void);
++bool efi_bgrt_probe(void);
+
+ /* The BGRT data itself; only valid if bgrt_image != NULL. */
+ extern void *bgrt_image;
+@@ -15,6 +16,7 @@ extern struct acpi_table_bgrt *bgrt_tab;
+ #else /* !CONFIG_ACPI_BGRT */
+
+ static inline void efi_bgrt_init(void) {}
++static inline bool efi_bgrt_probe(void) { return false; }
+
+ #endif /* !CONFIG_ACPI_BGRT */
+
+diff --git a/meta/cfg/kernel-cache/bsp/quark/quark.cfg b/meta/cfg/kernel-cache/bsp/quark/quark.cfg
+new file mode 100644
+index 0000000..30b2e33
+--- /dev/null
++++ b/meta/cfg/kernel-cache/bsp/quark/quark.cfg
+@@ -0,0 +1,3044 @@
++#
++# Automatically generated file; DO NOT EDIT.
++# Linux/i386 3.8.7 Kernel Configuration
++#
++# CONFIG_64BIT is not set
++CONFIG_X86_32=y
++CONFIG_X86=y
++CONFIG_INSTRUCTION_DECODER=y
++CONFIG_OUTPUT_FORMAT="elf32-i386"
++CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_MMU=y
++CONFIG_NEED_SG_DMA_LENGTH=y
++CONFIG_GENERIC_ISA_DMA=y
++CONFIG_GENERIC_BUG=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_GPIO=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_ARCH_HAS_CPU_RELAX=y
++CONFIG_ARCH_HAS_DEFAULT_IDLE=y
++CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
++CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
++CONFIG_HAVE_SETUP_PER_CPU_AREA=y
++CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
++CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
++CONFIG_ARCH_HIBERNATION_POSSIBLE=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++# CONFIG_ZONE_DMA32 is not set
++# CONFIG_AUDIT_ARCH is not set
++CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
++CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
++CONFIG_X86_32_LAZY_GS=y
++CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
++CONFIG_ARCH_SUPPORTS_UPROBES=y
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_HAVE_IRQ_WORK=y
++CONFIG_IRQ_WORK=y
++CONFIG_BUILDTIME_EXTABLE_SORT=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_BZIP2=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_XZ=y
++CONFIG_HAVE_KERNEL_LZO=y
++# CONFIG_KERNEL_GZIP is not set
++# CONFIG_KERNEL_BZIP2 is not set
++CONFIG_KERNEL_LZMA=y
++# CONFIG_KERNEL_XZ is not set
++# CONFIG_KERNEL_LZO is not set
++CONFIG_DEFAULT_HOSTNAME="(none)"
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++# CONFIG_FHANDLE is not set
++# CONFIG_AUDIT is not set
++CONFIG_HAVE_GENERIC_HARDIRQS=y
++
++#
++# IRQ subsystem
++#
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_IRQ_SHOW=y
++CONFIG_GENERIC_IRQ_CHIP=y
++CONFIG_IRQ_DOMAIN=y
++# CONFIG_IRQ_DOMAIN_DEBUG is not set
++CONFIG_IRQ_FORCED_THREADING=y
++CONFIG_SPARSE_IRQ=y
++CONFIG_CLOCKSOURCE_WATCHDOG=y
++CONFIG_KTIME_SCALAR=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
++CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
++CONFIG_GENERIC_CMOS_UPDATE=y
++
++#
++# Timers subsystem
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++CONFIG_HIGH_RES_TIMERS=y
++
++#
++# CPU/Task time and stats accounting
++#
++CONFIG_TICK_CPU_ACCOUNTING=y
++# CONFIG_IRQ_TIME_ACCOUNTING is not set
++CONFIG_BSD_PROCESS_ACCT=y
++# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_TASKSTATS is not set
++
++#
++# RCU Subsystem
++#
++CONFIG_TINY_RCU=y
++# CONFIG_PREEMPT_RCU is not set
++# CONFIG_TREE_RCU_TRACE is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
++CONFIG_LOG_BUF_SHIFT=18
++CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
++CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
++CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
++CONFIG_CGROUPS=y
++# CONFIG_CGROUP_DEBUG is not set
++CONFIG_CGROUP_FREEZER=y
++# CONFIG_CGROUP_DEVICE is not set
++CONFIG_CPUSETS=y
++CONFIG_PROC_PID_CPUSET=y
++CONFIG_CGROUP_CPUACCT=y
++CONFIG_RESOURCE_COUNTERS=y
++# CONFIG_MEMCG is not set
++# CONFIG_CGROUP_HUGETLB is not set
++# CONFIG_CGROUP_PERF is not set
++CONFIG_CGROUP_SCHED=y
++CONFIG_FAIR_GROUP_SCHED=y
++# CONFIG_CFS_BANDWIDTH is not set
++# CONFIG_RT_GROUP_SCHED is not set
++# CONFIG_BLK_CGROUP is not set
++# CONFIG_CHECKPOINT_RESTORE is not set
++CONFIG_NAMESPACES=y
++CONFIG_UTS_NS=y
++CONFIG_IPC_NS=y
++# CONFIG_USER_NS is not set
++CONFIG_PID_NS=y
++CONFIG_NET_NS=y
++CONFIG_UIDGID_CONVERTED=y
++# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
++# CONFIG_SCHED_AUTOGROUP is not set
++# CONFIG_SYSFS_DEPRECATED is not set
++CONFIG_RELAY=y
++CONFIG_BLK_DEV_INITRD=y
++CONFIG_INITRAMFS_SOURCE=""
++CONFIG_RD_GZIP=y
++CONFIG_RD_BZIP2=y
++CONFIG_RD_LZMA=y
++# CONFIG_RD_XZ is not set
++# CONFIG_RD_LZO is not set
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EXPERT=y
++CONFIG_HAVE_UID16=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_SYSCTL_EXCEPTION_TRACE=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++# CONFIG_PCSPKR_PLATFORM is not set
++CONFIG_HAVE_PCSPKR_PLATFORM=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++CONFIG_AIO=y
++CONFIG_EMBEDDED=y
++CONFIG_HAVE_PERF_EVENTS=y
++
++#
++# Kernel Performance Events And Counters
++#
++CONFIG_PERF_EVENTS=y
++# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
++CONFIG_VM_EVENT_COUNTERS=y
++CONFIG_PCI_QUIRKS=y
++CONFIG_SLUB_DEBUG=y
++# CONFIG_COMPAT_BRK is not set
++# CONFIG_SLAB is not set
++CONFIG_SLUB=y
++# CONFIG_SLOB is not set
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_OPROFILE_NMI_TIMER=y
++# CONFIG_KPROBES is not set
++CONFIG_JUMP_LABEL=y
++CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
++CONFIG_HAVE_IOREMAP_PROT=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_OPTPROBES=y
++CONFIG_HAVE_ARCH_TRACEHOOK=y
++CONFIG_HAVE_DMA_ATTRS=y
++CONFIG_HAVE_DMA_CONTIGUOUS=y
++CONFIG_GENERIC_SMP_IDLE_THREAD=y
++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
++CONFIG_HAVE_DMA_API_DEBUG=y
++CONFIG_HAVE_HW_BREAKPOINT=y
++CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
++CONFIG_HAVE_USER_RETURN_NOTIFIER=y
++CONFIG_HAVE_PERF_EVENTS_NMI=y
++CONFIG_HAVE_PERF_REGS=y
++CONFIG_HAVE_PERF_USER_STACK_DUMP=y
++CONFIG_HAVE_ARCH_JUMP_LABEL=y
++CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
++CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
++CONFIG_HAVE_CMPXCHG_LOCAL=y
++CONFIG_HAVE_CMPXCHG_DOUBLE=y
++CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
++CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
++CONFIG_SECCOMP_FILTER=y
++CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
++CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
++CONFIG_MODULES_USE_ELF_REL=y
++CONFIG_GENERIC_SIGALTSTACK=y
++CONFIG_CLONE_BACKWARDS=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_GCOV_KERNEL is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_SLABINFO=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++CONFIG_MODULES=y
++# CONFIG_MODULE_FORCE_LOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_MODULE_SIG is not set
++CONFIG_BLOCK=y
++# CONFIG_LBDAF is not set
++CONFIG_BLK_DEV_BSG=y
++# CONFIG_BLK_DEV_BSGLIB is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_BSD_DISKLABEL=y
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++# CONFIG_SYSV68_PARTITION is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
++CONFIG_INLINE_READ_UNLOCK=y
++CONFIG_INLINE_READ_UNLOCK_IRQ=y
++CONFIG_INLINE_WRITE_UNLOCK=y
++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
++CONFIG_FREEZER=y
++
++#
++# Processor type and features
++#
++# CONFIG_ZONE_DMA is not set
++# CONFIG_SMP is not set
++CONFIG_X86_MPPARSE=y
++CONFIG_X86_EXTENDED_PLATFORM=y
++CONFIG_INTEL_QUARK_X1000_SOC=y
++# CONFIG_X86_WANT_INTEL_MID is not set
++# CONFIG_X86_RDC321X is not set
++CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
++
++#
++# Intel Media SOC Gen3 support
++#
++CONFIG_ARCH_GEN3=y
++# CONFIG_X86_32_IRIS is not set
++CONFIG_SCHED_OMIT_FRAME_POINTER=y
++# CONFIG_PARAVIRT_GUEST is not set
++CONFIG_NO_BOOTMEM=y
++# CONFIG_MEMTEST is not set
++# CONFIG_M486 is not set
++# CONFIG_M586 is not set
++CONFIG_M586TSC=y
++# CONFIG_M586MMX is not set
++# CONFIG_M686 is not set
++# CONFIG_MPENTIUMII is not set
++# CONFIG_MPENTIUMIII is not set
++# CONFIG_MPENTIUMM is not set
++# CONFIG_MPENTIUM4 is not set
++# CONFIG_MK6 is not set
++# CONFIG_MK7 is not set
++# CONFIG_MK8 is not set
++# CONFIG_MCRUSOE is not set
++# CONFIG_MEFFICEON is not set
++# CONFIG_MWINCHIPC6 is not set
++# CONFIG_MWINCHIP3D is not set
++# CONFIG_MELAN is not set
++# CONFIG_MGEODEGX1 is not set
++# CONFIG_MGEODE_LX is not set
++# CONFIG_MCYRIXIII is not set
++# CONFIG_MVIAC3_2 is not set
++# CONFIG_MVIAC7 is not set
++# CONFIG_MCORE2 is not set
++# CONFIG_MATOM is not set
++CONFIG_X86_GENERIC=y
++CONFIG_X86_INTERNODE_CACHE_SHIFT=6
++CONFIG_X86_L1_CACHE_SHIFT=6
++# CONFIG_X86_PPRO_FENCE is not set
++CONFIG_X86_F00F_BUG=y
++CONFIG_X86_ALIGNMENT_16=y
++CONFIG_X86_INTEL_USERCOPY=y
++CONFIG_X86_TSC=y
++CONFIG_X86_CMPXCHG64=y
++CONFIG_X86_MINIMUM_CPU_FAMILY=5
++# CONFIG_PROCESSOR_SELECT is not set
++CONFIG_CPU_SUP_INTEL=y
++CONFIG_CPU_SUP_CYRIX_32=y
++CONFIG_CPU_SUP_AMD=y
++CONFIG_CPU_SUP_CENTAUR=y
++CONFIG_CPU_SUP_TRANSMETA_32=y
++CONFIG_CPU_SUP_UMC_32=y
++CONFIG_HPET_TIMER=y
++CONFIG_HPET_EMULATE_RTC=y
++CONFIG_DMI=y
++CONFIG_NR_CPUS=1
++# CONFIG_PREEMPT_NONE is not set
++CONFIG_PREEMPT_VOLUNTARY=y
++# CONFIG_PREEMPT is not set
++CONFIG_X86_UP_APIC=y
++CONFIG_X86_UP_IOAPIC=y
++CONFIG_X86_LOCAL_APIC=y
++CONFIG_X86_IO_APIC=y
++# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
++CONFIG_X86_MCE=y
++CONFIG_X86_MCE_INTEL=y
++# CONFIG_X86_MCE_AMD is not set
++# CONFIG_X86_ANCIENT_MCE is not set
++CONFIG_X86_MCE_THRESHOLD=y
++# CONFIG_X86_MCE_INJECT is not set
++CONFIG_X86_THERMAL_VECTOR=y
++CONFIG_VM86=y
++# CONFIG_TOSHIBA is not set
++# CONFIG_I8K is not set
++CONFIG_X86_REBOOTFIXUPS=y
++CONFIG_MICROCODE=y
++CONFIG_MICROCODE_INTEL=y
++# CONFIG_MICROCODE_AMD is not set
++CONFIG_MICROCODE_OLD_INTERFACE=y
++CONFIG_X86_MSR=y
++CONFIG_X86_CPUID=y
++# CONFIG_NOHIGHMEM is not set
++# CONFIG_HIGHMEM4G is not set
++CONFIG_HIGHMEM64G=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_HIGHMEM=y
++CONFIG_X86_PAE=y
++CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
++CONFIG_ARCH_DMA_ADDR_T_64BIT=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_ILLEGAL_POINTER_VALUE=0
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_SPARSEMEM_STATIC=y
++CONFIG_HAVE_MEMBLOCK=y
++CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
++CONFIG_ARCH_DISCARD_MEMBLOCK=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_COMPACTION is not set
++CONFIG_PHYS_ADDR_T_64BIT=y
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_BOUNCE=y
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
++# CONFIG_MEMORY_FAILURE is not set
++# CONFIG_TRANSPARENT_HUGEPAGE is not set
++CONFIG_CROSS_MEMORY_ATTACH=y
++CONFIG_NEED_PER_CPU_KM=y
++# CONFIG_CLEANCACHE is not set
++# CONFIG_HIGHPTE is not set
++# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
++CONFIG_X86_RESERVE_LOW=64
++# CONFIG_MATH_EMULATION is not set
++# CONFIG_MTRR is not set
++# CONFIG_ARCH_RANDOM is not set
++CONFIG_X86_SMAP=y
++CONFIG_EFI=y
++CONFIG_EFI_STUB=y
++CONFIG_EFI_CAPSULE=m
++CONFIG_SECCOMP=y
++# CONFIG_CC_STACKPROTECTOR is not set
++CONFIG_HZ_100=y
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_300 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++CONFIG_SCHED_HRTICK=y
++CONFIG_KEXEC=y
++# CONFIG_CRASH_DUMP is not set
++CONFIG_PHYSICAL_START=0x400000
++# CONFIG_RELOCATABLE is not set
++CONFIG_PHYSICAL_ALIGN=0x1000000
++# CONFIG_COMPAT_VDSO is not set
++# CONFIG_CMDLINE_BOOL is not set
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++
++#
++# Power management and ACPI options
++#
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_PM_SLEEP=y
++# CONFIG_PM_AUTOSLEEP is not set
++# CONFIG_PM_WAKELOCKS is not set
++CONFIG_PM_RUNTIME=y
++CONFIG_PM=y
++CONFIG_PM_DEBUG=y
++# CONFIG_PM_ADVANCED_DEBUG is not set
++# CONFIG_PM_TEST_SUSPEND is not set
++CONFIG_PM_SLEEP_DEBUG=y
++CONFIG_PM_TRACE=y
++CONFIG_PM_TRACE_RTC=y
++CONFIG_ACPI=y
++CONFIG_ACPI_SLEEP=y
++CONFIG_ACPI_PROCFS=y
++CONFIG_ACPI_PROCFS_POWER=y
++CONFIG_ACPI_EC_DEBUGFS=y
++# CONFIG_ACPI_PROC_EVENT is not set
++CONFIG_ACPI_AC=y
++# CONFIG_ACPI_BATTERY is not set
++CONFIG_ACPI_BUTTON=y
++# CONFIG_ACPI_FAN is not set
++# CONFIG_ACPI_DOCK is not set
++CONFIG_ACPI_I2C=y
++CONFIG_ACPI_PROCESSOR=y
++# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
++CONFIG_ACPI_THERMAL=y
++# CONFIG_ACPI_CUSTOM_DSDT is not set
++# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
++CONFIG_ACPI_BLACKLIST_YEAR=0
++CONFIG_ACPI_DEBUG=y
++# CONFIG_ACPI_DEBUG_FUNC_TRACE is not set
++CONFIG_ACPI_PCI_SLOT=y
++CONFIG_X86_PM_TIMER=y
++# CONFIG_ACPI_CONTAINER is not set
++# CONFIG_ACPI_SBS is not set
++# CONFIG_ACPI_HED is not set
++# CONFIG_ACPI_CUSTOM_METHOD is not set
++# CONFIG_ACPI_BGRT is not set
++# CONFIG_ACPI_APEI is not set
++# CONFIG_SFI is not set
++# CONFIG_APM is not set
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++CONFIG_CPU_IDLE=y
++# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
++# CONFIG_INTEL_IDLE is not set
++
++#
++# Bus options (PCI etc.)
++#
++CONFIG_PCI=y
++# CONFIG_PCI_GOBIOS is not set
++# CONFIG_PCI_GOMMCONFIG is not set
++# CONFIG_PCI_GODIRECT is not set
++CONFIG_PCI_GOANY=y
++CONFIG_PCI_BIOS=y
++CONFIG_PCI_DIRECT=y
++CONFIG_PCI_MMCONFIG=y
++CONFIG_PCI_DOMAINS=y
++# CONFIG_PCI_CNB20LE_QUIRK is not set
++CONFIG_PCIEPORTBUS=y
++CONFIG_PCIEAER=y
++# CONFIG_PCIE_ECRC is not set
++# CONFIG_PCIEAER_INJECT is not set
++CONFIG_PCIEASPM=y
++# CONFIG_PCIEASPM_DEBUG is not set
++CONFIG_PCIEASPM_DEFAULT=y
++# CONFIG_PCIEASPM_POWERSAVE is not set
++# CONFIG_PCIEASPM_PERFORMANCE is not set
++CONFIG_PCIE_PME=y
++CONFIG_ARCH_SUPPORTS_MSI=y
++CONFIG_PCI_MSI=y
++CONFIG_PCI_DEBUG=y
++# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
++# CONFIG_PCI_STUB is not set
++CONFIG_HT_IRQ=y
++# CONFIG_PCI_IOV is not set
++# CONFIG_PCI_PRI is not set
++# CONFIG_PCI_PASID is not set
++CONFIG_PCI_IOAPIC=y
++CONFIG_PCI_LABEL=y
++CONFIG_ISA_DMA_API=y
++# CONFIG_ISA is not set
++# CONFIG_SCx200 is not set
++# CONFIG_ALIX is not set
++# CONFIG_NET5501 is not set
++# CONFIG_GEOS is not set
++CONFIG_AMD_NB=y
++# CONFIG_PCCARD is not set
++# CONFIG_HOTPLUG_PCI is not set
++# CONFIG_RAPIDIO is not set
++
++#
++# Executable file formats / Emulations
++#
++CONFIG_BINFMT_ELF=y
++CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
++CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++CONFIG_COREDUMP=y
++CONFIG_HAVE_ATOMIC_IOMAP=y
++CONFIG_HAVE_TEXT_POKE_SMP=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_DIAG is not set
++CONFIG_UNIX=y
++# CONFIG_UNIX_DIAG is not set
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
++# CONFIG_XFRM_SUB_POLICY is not set
++# CONFIG_XFRM_MIGRATE is not set
++# CONFIG_XFRM_STATISTICS is not set
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE_DEMUX is not set
++# CONFIG_ARPD is not set
++CONFIG_SYN_COOKIES=y
++# CONFIG_NET_IPVTI is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
++CONFIG_INET_XFRM_MODE_BEET=y
++CONFIG_INET_LRO=y
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_UDP_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++CONFIG_IPV6=m
++# CONFIG_IPV6_PRIVACY is not set
++# CONFIG_IPV6_ROUTER_PREF is not set
++# CONFIG_IPV6_OPTIMISTIC_DAD is not set
++# CONFIG_INET6_AH is not set
++# CONFIG_INET6_ESP is not set
++# CONFIG_INET6_IPCOMP is not set
++# CONFIG_IPV6_MIP6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
++CONFIG_INET6_XFRM_MODE_TRANSPORT=m
++CONFIG_INET6_XFRM_MODE_TUNNEL=m
++CONFIG_INET6_XFRM_MODE_BEET=m
++# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
++# CONFIG_IPV6_SIT is not set
++# CONFIG_IPV6_TUNNEL is not set
++# CONFIG_IPV6_GRE is not set
++# CONFIG_IPV6_MULTIPLE_TABLES is not set
++# CONFIG_IPV6_MROUTE is not set
++# CONFIG_NETLABEL is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++CONFIG_STP=m
++CONFIG_GARP=m
++# CONFIG_BRIDGE is not set
++CONFIG_HAVE_NET_DSA=y
++CONFIG_VLAN_8021Q=m
++CONFIG_VLAN_8021Q_GVRP=y
++# CONFIG_DECNET is not set
++CONFIG_LLC=m
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++# CONFIG_DNS_RESOLVER is not set
++# CONFIG_BATMAN_ADV is not set
++# CONFIG_OPENVSWITCH is not set
++# CONFIG_NETPRIO_CGROUP is not set
++CONFIG_BQL=y
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++CONFIG_BT=m
++CONFIG_BT_RFCOMM=m
++CONFIG_BT_RFCOMM_TTY=y
++CONFIG_BT_BNEP=m
++CONFIG_BT_BNEP_MC_FILTER=y
++CONFIG_BT_BNEP_PROTO_FILTER=y
++CONFIG_BT_HIDP=m
++
++#
++# Bluetooth device drivers
++#
++CONFIG_BT_HCIBTUSB=m
++# CONFIG_BT_HCIBTSDIO is not set
++# CONFIG_BT_HCIUART is not set
++# CONFIG_BT_HCIBCM203X is not set
++# CONFIG_BT_HCIBPA10X is not set
++# CONFIG_BT_HCIBFUSB is not set
++CONFIG_BT_HCIVHCI=m
++# CONFIG_BT_MRVL is not set
++# CONFIG_BT_ATH3K is not set
++# CONFIG_AF_RXRPC is not set
++CONFIG_WIRELESS=y
++CONFIG_WEXT_CORE=y
++CONFIG_WEXT_PROC=y
++CONFIG_CFG80211=m
++# CONFIG_NL80211_TESTMODE is not set
++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
++# CONFIG_CFG80211_REG_DEBUG is not set
++# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
++CONFIG_CFG80211_DEFAULT_PS=y
++# CONFIG_CFG80211_DEBUGFS is not set
++# CONFIG_CFG80211_INTERNAL_REGDB is not set
++CONFIG_CFG80211_WEXT=y
++# CONFIG_LIB80211 is not set
++CONFIG_MAC80211=m
++CONFIG_MAC80211_HAS_RC=y
++# CONFIG_MAC80211_RC_PID is not set
++CONFIG_MAC80211_RC_MINSTREL=y
++CONFIG_MAC80211_RC_MINSTREL_HT=y
++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
++# CONFIG_MAC80211_MESH is not set
++CONFIG_MAC80211_LEDS=y
++# CONFIG_MAC80211_DEBUGFS is not set
++# CONFIG_MAC80211_MESSAGE_TRACING is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++# CONFIG_WIMAX is not set
++CONFIG_RFKILL=m
++CONFIG_RFKILL_LEDS=y
++CONFIG_RFKILL_INPUT=y
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++# CONFIG_CEPH_LIB is not set
++# CONFIG_NFC is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_DEVTMPFS=y
++CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=y
++CONFIG_FIRMWARE_IN_KERNEL=y
++CONFIG_EXTRA_FIRMWARE=""
++# CONFIG_DEBUG_DRIVER is not set
++CONFIG_DEBUG_DEVRES=y
++# CONFIG_SYS_HYPERVISOR is not set
++# CONFIG_GENERIC_CPU_DEVICES is not set
++CONFIG_DMA_SHARED_BUFFER=y
++# CONFIG_CMA is not set
++
++#
++# Bus devices
++#
++# CONFIG_CONNECTOR is not set
++CONFIG_MTD=y
++# CONFIG_MTD_TESTS is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=m
++CONFIG_MTD_BLKDEVS=m
++CONFIG_MTD_BLOCK=m
++# CONFIG_MTD_BLOCK_RO is not set
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_TS5500 is not set
++# CONFIG_MTD_INTEL_VR_NOR is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_DATAFLASH is not set
++CONFIG_MTD_M25P80=m
++CONFIG_M25PXX_USE_FAST_READ=y
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_MTD_QRK_ROM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOCG3 is not set
++# CONFIG_MTD_NAND is not set
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_PNP=y
++# CONFIG_PNP_DEBUG_MESSAGES is not set
++
++#
++# Protocols
++#
++CONFIG_PNPACPI=y
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_NVME is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=1
++CONFIG_BLK_DEV_RAM_SIZE=81920
++# CONFIG_BLK_DEV_XIP is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_RBD is not set
++
++#
++# Misc devices
++#
++# CONFIG_SENSORS_LIS3LV02D is not set
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_IBM_ASM is not set
++# CONFIG_PHANTOM is not set
++# CONFIG_INTEL_MID_PTI is not set
++# CONFIG_SGI_IOC4 is not set
++# CONFIG_TIFM_CORE is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_HP_ILO is not set
++# CONFIG_APDS9802ALS is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_ISL29020 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_SENSORS_BH1780 is not set
++# CONFIG_SENSORS_BH1770 is not set
++# CONFIG_SENSORS_APDS990X is not set
++# CONFIG_HMC6352 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_VMWARE_BALLOON is not set
++# CONFIG_BMP085_I2C is not set
++# CONFIG_BMP085_SPI is not set
++# CONFIG_PCH_PHUB is not set
++# CONFIG_USB_SWITCH_FSA9480 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++CONFIG_EEPROM_AT24=m
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_EEPROM_93XX46 is not set
++# CONFIG_CB710_CORE is not set
++
++#
++# Texas Instruments shared transport line discipline
++#
++# CONFIG_TI_ST is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++
++#
++# Altera FPGA firmware download module
++#
++# CONFIG_ALTERA_STAPL is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++
++#
++# SCSI Transports
++#
++CONFIG_SCSI_SPI_ATTRS=y
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++# CONFIG_TARGET_CORE is not set
++# CONFIG_FUSION is not set
++
++#
++# IEEE 1394 (FireWire) support
++#
++# CONFIG_FIREWIRE is not set
++# CONFIG_FIREWIRE_NOSY is not set
++# CONFIG_I2O is not set
++# CONFIG_MACINTOSH_DRIVERS is not set
++CONFIG_NETDEVICES=y
++CONFIG_NET_CORE=y
++# CONFIG_BONDING is not set
++# CONFIG_DUMMY is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_NET_FC is not set
++CONFIG_MII=y
++# CONFIG_NET_TEAM is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_VXLAN is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++# CONFIG_ARCNET is not set
++
++#
++# CAIF transport drivers
++#
++
++#
++# Distributed Switch Architecture drivers
++#
++# CONFIG_NET_DSA_MV88E6XXX is not set
++# CONFIG_NET_DSA_MV88E6060 is not set
++# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
++# CONFIG_NET_DSA_MV88E6131 is not set
++# CONFIG_NET_DSA_MV88E6123_61_65 is not set
++CONFIG_ETHERNET=y
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_NET_VENDOR_ADAPTEC is not set
++# CONFIG_NET_VENDOR_ALTEON is not set
++# CONFIG_NET_VENDOR_AMD is not set
++# CONFIG_NET_VENDOR_ATHEROS is not set
++CONFIG_NET_CADENCE=y
++# CONFIG_ARM_AT91_ETHER is not set
++# CONFIG_MACB is not set
++# CONFIG_NET_VENDOR_BROADCOM is not set
++# CONFIG_NET_VENDOR_BROCADE is not set
++# CONFIG_NET_CALXEDA_XGMAC is not set
++# CONFIG_NET_VENDOR_CHELSIO is not set
++# CONFIG_NET_VENDOR_CISCO is not set
++# CONFIG_DNET is not set
++# CONFIG_NET_VENDOR_DEC is not set
++# CONFIG_NET_VENDOR_DLINK is not set
++# CONFIG_NET_VENDOR_EMULEX is not set
++# CONFIG_NET_VENDOR_EXAR is not set
++# CONFIG_NET_VENDOR_HP is not set
++CONFIG_NET_VENDOR_INTEL=y
++# CONFIG_E100 is not set
++CONFIG_E1000=m
++# CONFIG_E1000E is not set
++# CONFIG_IGB is not set
++# CONFIG_IGBVF is not set
++# CONFIG_IXGB is not set
++# CONFIG_IXGBE is not set
++# CONFIG_IXGBEVF is not set
++# CONFIG_NET_VENDOR_I825XX is not set
++# CONFIG_IP1000 is not set
++# CONFIG_JME is not set
++# CONFIG_NET_VENDOR_MARVELL is not set
++# CONFIG_NET_VENDOR_MELLANOX is not set
++# CONFIG_NET_VENDOR_MICREL is not set
++# CONFIG_NET_VENDOR_MICROCHIP is not set
++# CONFIG_NET_VENDOR_MYRI is not set
++# CONFIG_FEALNX is not set
++# CONFIG_NET_VENDOR_NATSEMI is not set
++# CONFIG_NET_VENDOR_NVIDIA is not set
++# CONFIG_NET_VENDOR_OKI is not set
++# CONFIG_ETHOC is not set
++# CONFIG_NET_PACKET_ENGINE is not set
++# CONFIG_NET_VENDOR_QLOGIC is not set
++# CONFIG_NET_VENDOR_REALTEK is not set
++# CONFIG_NET_VENDOR_RDC is not set
++# CONFIG_NET_VENDOR_SEEQ is not set
++# CONFIG_NET_VENDOR_SILAN is not set
++# CONFIG_NET_VENDOR_SIS is not set
++# CONFIG_SFC is not set
++# CONFIG_NET_VENDOR_SMSC is not set
++CONFIG_NET_VENDOR_STMICRO=y
++CONFIG_STMMAC_ETH=m
++# CONFIG_STMMAC_PLATFORM is not set
++CONFIG_STMMAC_PCI=y
++# CONFIG_STMMAC_DEBUG_FS is not set
++CONFIG_STMMAC_DA=y
++# CONFIG_STMMAC_PTP is not set
++CONFIG_STMMAC_RING=y
++# CONFIG_STMMAC_CHAINED is not set
++# CONFIG_NET_VENDOR_SUN is not set
++# CONFIG_NET_VENDOR_TEHUTI is not set
++# CONFIG_NET_VENDOR_TI is not set
++# CONFIG_NET_VENDOR_VIA is not set
++# CONFIG_NET_VENDOR_WIZNET is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_NET_SB1000 is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_AT803X_PHY is not set
++# CONFIG_AMD_PHY is not set
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++# CONFIG_SMSC_PHY is not set
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_BCM87XX_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++# CONFIG_MICREL_KS8995MA is not set
++CONFIG_PPP=m
++# CONFIG_PPP_BSDCOMP is not set
++CONFIG_PPP_DEFLATE=m
++# CONFIG_PPP_FILTER is not set
++# CONFIG_PPP_MPPE is not set
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPPOE is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_SLIP is not set
++CONFIG_SLHC=m
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_HSO is not set
++# CONFIG_USB_IPHETH is not set
++CONFIG_WLAN=y
++# CONFIG_LIBERTAS_THINFIRM is not set
++# CONFIG_AIRO is not set
++# CONFIG_ATMEL is not set
++# CONFIG_AT76C50X_USB is not set
++# CONFIG_PRISM54 is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8180 is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_ADM8211 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_MWL8K is not set
++# CONFIG_ATH_CARDS is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_BRCMFMAC is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_IPW2100 is not set
++# CONFIG_IPW2200 is not set
++CONFIG_IWLWIFI=m
++CONFIG_IWLDVM=m
++
++#
++# Debugging Options
++#
++# CONFIG_IWLWIFI_DEBUG is not set
++CONFIG_IWLWIFI_P2P=y
++# CONFIG_IWL4965 is not set
++# CONFIG_IWL3945 is not set
++# CONFIG_LIBERTAS is not set
++# CONFIG_HERMES is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_RT2X00 is not set
++# CONFIG_RTL8192CE is not set
++# CONFIG_RTL8192SE is not set
++# CONFIG_RTL8192DE is not set
++# CONFIG_RTL8723AE is not set
++# CONFIG_RTL8192CU is not set
++# CONFIG_WL_TI is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_MWIFIEX is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++# CONFIG_WAN is not set
++# CONFIG_VMXNET3 is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++# CONFIG_INPUT_MATRIXKMAP is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=m
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++# CONFIG_INPUT_TOUCHSCREEN is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_VT_CONSOLE_SLEEP=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=32
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_SYNCLINK is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_SYNCLINK_GT is not set
++# CONFIG_NOZOMI is not set
++# CONFIG_ISI is not set
++# CONFIG_N_HDLC is not set
++# CONFIG_N_GSM is not set
++# CONFIG_TRACE_SINK is not set
++CONFIG_DEVKMEM=y
++# CONFIG_STALDRV is not set
++
++#
++# Serial drivers
++#
++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_NR_UARTS=8
++CONFIG_SERIAL_8250_RUNTIME_UARTS=2
++CONFIG_SERIAL_8250_EXTENDED=y
++CONFIG_SERIAL_8250_MANY_PORTS=y
++CONFIG_SERIAL_8250_SHARE_IRQ=y
++CONFIG_SERIAL_8250_DETECT_IRQ=y
++CONFIG_SERIAL_8250_RSA=y
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++# CONFIG_SERIAL_MAX310X is not set
++# CONFIG_SERIAL_MFD_HSU is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_JSM is not set
++# CONFIG_SERIAL_SCCNXP is not set
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++# CONFIG_SERIAL_IFX6X60 is not set
++CONFIG_SERIAL_QUARK_UART=m
++# CONFIG_SERIAL_PCH_UART is not set
++# CONFIG_SERIAL_ARC is not set
++# CONFIG_TTY_PRINTK is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++# CONFIG_SONYPI is not set
++# CONFIG_MWAVE is not set
++# CONFIG_PC8736x_GPIO is not set
++# CONFIG_NSC_GPIO is not set
++# CONFIG_RAW_DRIVER is not set
++CONFIG_HPET=y
++# CONFIG_HPET_MMAP is not set
++# CONFIG_HANGCHECK_TIMER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
++CONFIG_DEVPORT=y
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_COMPAT=y
++CONFIG_I2C_CHARDEV=m
++# CONFIG_I2C_MUX is not set
++CONFIG_I2C_HELPER_AUTO=y
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# PC SMBus host controller drivers
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_ISCH is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_SIS5595 is not set
++# CONFIG_I2C_SIS630 is not set
++# CONFIG_I2C_SIS96X is not set
++# CONFIG_I2C_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++
++#
++# ACPI drivers
++#
++# CONFIG_I2C_SCMI is not set
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_CBUS_GPIO is not set
++# CONFIG_I2C_EG20T is not set
++# CONFIG_I2C_GPIO is not set
++# CONFIG_I2C_INTEL_MID is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_PXA_PCI is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_DIOLAN_U2C is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_SCx200_ACB is not set
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++CONFIG_SPI_DEBUG=y
++CONFIG_GEN3_SPI=y
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++# CONFIG_SPI_ALTERA is not set
++CONFIG_SPI_BITBANG=y
++CONFIG_SPI_GPIO=y
++# CONFIG_SPI_OC_TINY is not set
++CONFIG_SPI_PXA2XX=m
++CONFIG_SPI_PXA2XX_PCI=m
++# CONFIG_SPI_CE5XX_SPI_SLAVE is not set
++# CONFIG_SPI_SC18IS602 is not set
++# CONFIG_SPI_TOPCLIFF_PCH is not set
++# CONFIG_SPI_XCOMM is not set
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++# CONFIG_SPI_LPC_SCH is not set
++
++#
++# SPI Protocol Masters
++#
++CONFIG_SPI_SPIDEV=m
++# CONFIG_SPI_TLE62X0 is not set
++# CONFIG_HSI is not set
++
++#
++# PPS support
++#
++CONFIG_PPS=m
++# CONFIG_PPS_DEBUG is not set
++
++#
++# PPS clients support
++#
++# CONFIG_PPS_CLIENT_KTIMER is not set
++# CONFIG_PPS_CLIENT_LDISC is not set
++# CONFIG_PPS_CLIENT_GPIO is not set
++
++#
++# PPS generators support
++#
++
++#
++# PTP clock support
++#
++CONFIG_PTP_1588_CLOCK=m
++
++#
++# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
++#
++CONFIG_PTP_1588_CLOCK_PCH=m
++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_ACPI=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO drivers:
++#
++# CONFIG_GPIO_GENERIC_PLATFORM is not set
++# CONFIG_GPIO_IT8761E is not set
++# CONFIG_GPIO_TS5500 is not set
++CONFIG_GPIO_SCH=m
++# CONFIG_GPIO_ICH is not set
++# CONFIG_GPIO_VX855 is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_SX150X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++# CONFIG_GPIO_BT8XX is not set
++# CONFIG_GPIO_AMD8111 is not set
++# CONFIG_GPIO_LANGWELL is not set
++# CONFIG_GPIO_PCH is not set
++# CONFIG_GPIO_ML_IOH is not set
++# CONFIG_GPIO_RDC321X is not set
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++# CONFIG_GPIO_74X164 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++
++#
++# USB GPIO expanders:
++#
++# CONFIG_W1 is not set
++CONFIG_POWER_SUPPLY=y
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_GENERIC_ADC_BATTERY is not set
++# CONFIG_TEST_POWER is not set
++# CONFIG_BATTERY_DS2780 is not set
++# CONFIG_BATTERY_DS2781 is not set
++# CONFIG_BATTERY_DS2782 is not set
++# CONFIG_BATTERY_SBS is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++# CONFIG_BATTERY_MAX17040 is not set
++# CONFIG_BATTERY_MAX17042 is not set
++# CONFIG_CHARGER_MAX8903 is not set
++# CONFIG_CHARGER_LP8727 is not set
++# CONFIG_CHARGER_GPIO is not set
++# CONFIG_CHARGER_BQ2415X is not set
++# CONFIG_CHARGER_SMB347 is not set
++# CONFIG_POWER_RESET is not set
++# CONFIG_POWER_AVS is not set
++# CONFIG_HWMON is not set
++CONFIG_THERMAL=y
++CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
++# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
++# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
++# CONFIG_FAIR_SHARE is not set
++CONFIG_STEP_WISE=y
++# CONFIG_USER_SPACE is not set
++# CONFIG_WATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++CONFIG_BCMA_POSSIBLE=y
++
++#
++# Broadcom specific AMBA
++#
++# CONFIG_BCMA is not set
++
++#
++# Multifunction device drivers
++#
++CONFIG_MFD_CORE=y
++# CONFIG_MFD_88PM860X is not set
++# CONFIG_MFD_88PM800 is not set
++# CONFIG_MFD_88PM805 is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_RTSX_PCI is not set
++# CONFIG_MFD_TI_AM335X_TSCADC is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_HTC_I2CPLD is not set
++# CONFIG_MFD_LM3533 is not set
++# CONFIG_TPS6105X is not set
++# CONFIG_TPS65010 is not set
++# CONFIG_TPS6507X is not set
++# CONFIG_MFD_TPS65217 is not set
++# CONFIG_MFD_TPS6586X is not set
++# CONFIG_MFD_TPS65910 is not set
++# CONFIG_MFD_TPS65912_I2C is not set
++# CONFIG_MFD_TPS65912_SPI is not set
++# CONFIG_MFD_TPS80031 is not set
++# CONFIG_TWL4030_CORE is not set
++# CONFIG_TWL6040_CORE is not set
++# CONFIG_MFD_STMPE is not set
++# CONFIG_MFD_TC3589X is not set
++# CONFIG_MFD_TMIO is not set
++# CONFIG_MFD_SMSC is not set
++# CONFIG_PMIC_DA903X is not set
++# CONFIG_MFD_DA9052_SPI is not set
++# CONFIG_MFD_DA9052_I2C is not set
++# CONFIG_MFD_DA9055 is not set
++# CONFIG_PMIC_ADP5520 is not set
++# CONFIG_MFD_LP8788 is not set
++# CONFIG_MFD_MAX77686 is not set
++# CONFIG_MFD_MAX77693 is not set
++# CONFIG_MFD_MAX8907 is not set
++# CONFIG_MFD_MAX8925 is not set
++# CONFIG_MFD_MAX8997 is not set
++# CONFIG_MFD_MAX8998 is not set
++# CONFIG_MFD_SEC_CORE is not set
++# CONFIG_MFD_ARIZONA_I2C is not set
++# CONFIG_MFD_ARIZONA_SPI is not set
++# CONFIG_MFD_WM8400 is not set
++# CONFIG_MFD_WM831X_I2C is not set
++# CONFIG_MFD_WM831X_SPI is not set
++# CONFIG_MFD_WM8350_I2C is not set
++# CONFIG_MFD_WM8994 is not set
++# CONFIG_MFD_PCF50633 is not set
++# CONFIG_MFD_MC13XXX_SPI is not set
++# CONFIG_MFD_MC13XXX_I2C is not set
++# CONFIG_ABX500_CORE is not set
++# CONFIG_EZX_PCAP is not set
++# CONFIG_MFD_CS5535 is not set
++# CONFIG_MFD_TIMBERDALE is not set
++CONFIG_CY8C9540A=m
++CONFIG_INTEL_QRK_GIP=m
++CONFIG_INTEL_QRK_GIP_TEST=m
++CONFIG_LPC_SCH=y
++# CONFIG_LPC_ICH is not set
++# CONFIG_MFD_RDC321X is not set
++# CONFIG_MFD_JANZ_CMODIO is not set
++# CONFIG_MFD_VX855 is not set
++# CONFIG_MFD_WL1273_CORE is not set
++# CONFIG_MFD_TPS65090 is not set
++# CONFIG_MFD_AAT2870_CORE is not set
++# CONFIG_MFD_RC5T583 is not set
++# CONFIG_MFD_PALMAS is not set
++# CONFIG_MFD_VIPERBOARD is not set
++# CONFIG_MFD_RETU is not set
++# CONFIG_MFD_AS3711 is not set
++# CONFIG_REGULATOR is not set
++CONFIG_MEDIA_SUPPORT=m
++
++#
++# Multimedia core support
++#
++CONFIG_MEDIA_CAMERA_SUPPORT=y
++# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
++# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
++# CONFIG_MEDIA_RADIO_SUPPORT is not set
++# CONFIG_MEDIA_RC_SUPPORT is not set
++# CONFIG_MEDIA_CONTROLLER is not set
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2=m
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
++CONFIG_VIDEOBUF2_CORE=m
++CONFIG_VIDEOBUF2_MEMOPS=m
++CONFIG_VIDEOBUF2_VMALLOC=m
++
++#
++# Media drivers
++#
++CONFIG_MEDIA_USB_SUPPORT=y
++
++#
++# Webcam devices
++#
++CONFIG_USB_VIDEO_CLASS=m
++CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
++# CONFIG_USB_GSPCA is not set
++# CONFIG_USB_PWC is not set
++# CONFIG_VIDEO_CPIA2 is not set
++# CONFIG_USB_ZR364XX is not set
++# CONFIG_USB_STKWEBCAM is not set
++# CONFIG_USB_S2255 is not set
++# CONFIG_USB_SN9C102 is not set
++
++#
++# Webcam, TV (analog/digital) USB devices
++#
++# CONFIG_VIDEO_EM28XX is not set
++# CONFIG_MEDIA_PCI_SUPPORT is not set
++# CONFIG_V4L_PLATFORM_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++# CONFIG_V4L_TEST_DRIVERS is not set
++
++#
++# Supported MMC/SDIO adapters
++#
++# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
++
++#
++# Media ancillary drivers (tuners, sensors, i2c, frontends)
++#
++
++#
++# Encoders, decoders, sensors and other helper chips
++#
++
++#
++# Audio decoders, processors and mixers
++#
++# CONFIG_VIDEO_TVAUDIO is not set
++# CONFIG_VIDEO_TDA7432 is not set
++# CONFIG_VIDEO_TDA9840 is not set
++# CONFIG_VIDEO_TEA6415C is not set
++# CONFIG_VIDEO_TEA6420 is not set
++# CONFIG_VIDEO_MSP3400 is not set
++# CONFIG_VIDEO_CS5345 is not set
++# CONFIG_VIDEO_CS53L32A is not set
++# CONFIG_VIDEO_TLV320AIC23B is not set
++# CONFIG_VIDEO_WM8775 is not set
++# CONFIG_VIDEO_WM8739 is not set
++# CONFIG_VIDEO_VP27SMPX is not set
++
++#
++# RDS decoders
++#
++# CONFIG_VIDEO_SAA6588 is not set
++
++#
++# Video decoders
++#
++# CONFIG_VIDEO_ADV7180 is not set
++# CONFIG_VIDEO_ADV7183 is not set
++# CONFIG_VIDEO_BT819 is not set
++# CONFIG_VIDEO_BT856 is not set
++# CONFIG_VIDEO_BT866 is not set
++# CONFIG_VIDEO_KS0127 is not set
++# CONFIG_VIDEO_SAA7110 is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_SAA7191 is not set
++# CONFIG_VIDEO_TVP514X is not set
++# CONFIG_VIDEO_TVP5150 is not set
++# CONFIG_VIDEO_TVP7002 is not set
++# CONFIG_VIDEO_VPX3220 is not set
++
++#
++# Video and audio decoders
++#
++# CONFIG_VIDEO_SAA717X is not set
++# CONFIG_VIDEO_CX25840 is not set
++
++#
++# MPEG video encoders
++#
++# CONFIG_VIDEO_CX2341X is not set
++
++#
++# Video encoders
++#
++# CONFIG_VIDEO_SAA7127 is not set
++# CONFIG_VIDEO_SAA7185 is not set
++# CONFIG_VIDEO_ADV7170 is not set
++# CONFIG_VIDEO_ADV7175 is not set
++# CONFIG_VIDEO_ADV7343 is not set
++# CONFIG_VIDEO_ADV7393 is not set
++# CONFIG_VIDEO_AK881X is not set
++
++#
++# Camera sensor devices
++#
++# CONFIG_VIDEO_OV7670 is not set
++# CONFIG_VIDEO_VS6624 is not set
++# CONFIG_VIDEO_MT9V011 is not set
++# CONFIG_VIDEO_TCM825X is not set
++# CONFIG_VIDEO_SR030PC30 is not set
++
++#
++# Flash devices
++#
++
++#
++# Video improvement chips
++#
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++
++#
++# Miscelaneous helper chips
++#
++# CONFIG_VIDEO_THS7303 is not set
++# CONFIG_VIDEO_M52790 is not set
++
++#
++# Sensors used on soc_camera driver
++#
++
++#
++# Customise DVB Frontends
++#
++# CONFIG_DVB_AU8522_V4L is not set
++# CONFIG_DVB_TUNER_DIB0070 is not set
++# CONFIG_DVB_TUNER_DIB0090 is not set
++
++#
++# Tools to develop new frontends
++#
++# CONFIG_DVB_DUMMY_FE is not set
++
++#
++# Graphics support
++#
++# CONFIG_AGP is not set
++# CONFIG_VGA_ARB is not set
++# CONFIG_VGA_SWITCHEROO is not set
++# CONFIG_DRM is not set
++# CONFIG_STUB_POULSBO is not set
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++# CONFIG_FB is not set
++# CONFIG_EXYNOS_VIDEO is not set
++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_SOUND=m
++# CONFIG_SOUND_OSS_CORE is not set
++CONFIG_SND=m
++CONFIG_SND_TIMER=m
++CONFIG_SND_PCM=m
++CONFIG_SND_HWDEP=m
++CONFIG_SND_RAWMIDI=m
++# CONFIG_SND_SEQUENCER is not set
++# CONFIG_SND_MIXER_OSS is not set
++# CONFIG_SND_PCM_OSS is not set
++# CONFIG_SND_HRTIMER is not set
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++CONFIG_SND_DMA_SGBUF=y
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++CONFIG_SND_DRIVERS=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_ALOOP is not set
++# CONFIG_SND_MTPAV is not set
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
++CONFIG_SND_PCI=y
++# CONFIG_SND_AD1889 is not set
++# CONFIG_SND_ALS300 is not set
++# CONFIG_SND_ALS4000 is not set
++# CONFIG_SND_ALI5451 is not set
++# CONFIG_SND_ASIHPI is not set
++# CONFIG_SND_ATIIXP is not set
++# CONFIG_SND_ATIIXP_MODEM is not set
++# CONFIG_SND_AU8810 is not set
++# CONFIG_SND_AU8820 is not set
++# CONFIG_SND_AU8830 is not set
++# CONFIG_SND_AW2 is not set
++# CONFIG_SND_AZT3328 is not set
++# CONFIG_SND_BT87X is not set
++# CONFIG_SND_CA0106 is not set
++# CONFIG_SND_CMIPCI is not set
++# CONFIG_SND_OXYGEN is not set
++# CONFIG_SND_CS4281 is not set
++# CONFIG_SND_CS46XX is not set
++# CONFIG_SND_CS5530 is not set
++# CONFIG_SND_CS5535AUDIO is not set
++# CONFIG_SND_CTXFI is not set
++# CONFIG_SND_DARLA20 is not set
++# CONFIG_SND_GINA20 is not set
++# CONFIG_SND_LAYLA20 is not set
++# CONFIG_SND_DARLA24 is not set
++# CONFIG_SND_GINA24 is not set
++# CONFIG_SND_LAYLA24 is not set
++# CONFIG_SND_MONA is not set
++# CONFIG_SND_MIA is not set
++# CONFIG_SND_ECHO3G is not set
++# CONFIG_SND_INDIGO is not set
++# CONFIG_SND_INDIGOIO is not set
++# CONFIG_SND_INDIGODJ is not set
++# CONFIG_SND_INDIGOIOX is not set
++# CONFIG_SND_INDIGODJX is not set
++# CONFIG_SND_EMU10K1 is not set
++# CONFIG_SND_EMU10K1X is not set
++# CONFIG_SND_ENS1370 is not set
++# CONFIG_SND_ENS1371 is not set
++# CONFIG_SND_ES1938 is not set
++# CONFIG_SND_ES1968 is not set
++# CONFIG_SND_FM801 is not set
++# CONFIG_SND_HDA_INTEL is not set
++# CONFIG_SND_HDSP is not set
++# CONFIG_SND_HDSPM is not set
++# CONFIG_SND_ICE1712 is not set
++# CONFIG_SND_ICE1724 is not set
++# CONFIG_SND_INTEL8X0 is not set
++# CONFIG_SND_INTEL8X0M is not set
++# CONFIG_SND_KORG1212 is not set
++# CONFIG_SND_LOLA is not set
++# CONFIG_SND_LX6464ES is not set
++# CONFIG_SND_MAESTRO3 is not set
++# CONFIG_SND_MIXART is not set
++# CONFIG_SND_NM256 is not set
++# CONFIG_SND_PCXHR is not set
++# CONFIG_SND_RIPTIDE is not set
++# CONFIG_SND_RME32 is not set
++# CONFIG_SND_RME96 is not set
++# CONFIG_SND_RME9652 is not set
++# CONFIG_SND_SIS7019 is not set
++# CONFIG_SND_SONICVIBES is not set
++# CONFIG_SND_TRIDENT is not set
++# CONFIG_SND_VIA82XX is not set
++# CONFIG_SND_VIA82XX_MODEM is not set
++# CONFIG_SND_VIRTUOSO is not set
++# CONFIG_SND_VX222 is not set
++# CONFIG_SND_YMFPCI is not set
++CONFIG_SND_SPI=y
++CONFIG_SND_USB=y
++CONFIG_SND_USB_AUDIO=m
++# CONFIG_SND_USB_UA101 is not set
++# CONFIG_SND_USB_USX2Y is not set
++# CONFIG_SND_USB_CAIAQ is not set
++# CONFIG_SND_USB_US122L is not set
++# CONFIG_SND_USB_6FIRE is not set
++# CONFIG_SND_SOC is not set
++# CONFIG_SOUND_PRIME is not set
++
++#
++# HID support
++#
++CONFIG_HID=y
++# CONFIG_HID_BATTERY_STRENGTH is not set
++# CONFIG_HIDRAW is not set
++# CONFIG_UHID is not set
++CONFIG_HID_GENERIC=y
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_ACRUX is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_AUREAL is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EMS_FF is not set
++# CONFIG_HID_ELECOM is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_HOLTEK is not set
++# CONFIG_HID_KEYTOUCH is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_UCLOGIC is not set
++# CONFIG_HID_WALTOP is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_ICADE is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LCPOWER is not set
++# CONFIG_HID_LENOVO_TPKBD is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MAGICMOUSE is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_MULTITOUCH is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_PRIMAX is not set
++# CONFIG_HID_PS3REMOTE is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_SAITEK is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_SPEEDLINK is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TIVO is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_WACOM is not set
++# CONFIG_HID_WIIMOTE is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++# CONFIG_HID_SENSOR_HUB is not set
++
++#
++# USB HID support
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# I2C HID support
++#
++# CONFIG_I2C_HID is not set
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB_ARCH_HAS_XHCI=y
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_COMMON=m
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB=m
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_SUSPEND is not set
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_DWC3 is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++# CONFIG_USB_XHCI_HCD is not set
++CONFIG_USB_EHCI_HCD=m
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_PCI=m
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++CONFIG_USB_OHCI_HCD=m
++# CONFIG_USB_OHCI_HCD_PLATFORM is not set
++# CONFIG_USB_EHCI_HCD_PLATFORM is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_UHCI_HCD=m
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_CHIPIDEA is not set
++# CONFIG_USB_RENESAS_USBHS is not set
++
++#
++# USB Device Class drivers
++#
++CONFIG_USB_ACM=m
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=m
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_REALTEK is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_STORAGE_ENE_UB6250 is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_CH341 is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_CP210X is not set
++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_FUNSOFT is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
++# CONFIG_USB_SERIAL_F81232 is not set
++# CONFIG_USB_SERIAL_GARMIN is not set
++# CONFIG_USB_SERIAL_IPW is not set
++# CONFIG_USB_SERIAL_IUU is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_KOBIL_SCT is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_METRO is not set
++# CONFIG_USB_SERIAL_MOS7720 is not set
++# CONFIG_USB_SERIAL_MOS7840 is not set
++# CONFIG_USB_SERIAL_MOTOROLA is not set
++# CONFIG_USB_SERIAL_NAVMAN is not set
++CONFIG_USB_SERIAL_PL2303=m
++# CONFIG_USB_SERIAL_OTI6858 is not set
++# CONFIG_USB_SERIAL_QCAUX is not set
++# CONFIG_USB_SERIAL_QUALCOMM is not set
++# CONFIG_USB_SERIAL_SPCP8X5 is not set
++# CONFIG_USB_SERIAL_HP4X is not set
++# CONFIG_USB_SERIAL_SAFE is not set
++# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
++# CONFIG_USB_SERIAL_SYMBOL is not set
++# CONFIG_USB_SERIAL_TI is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OPTION is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_SERIAL_OPTICON is not set
++# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
++# CONFIG_USB_SERIAL_ZIO is not set
++# CONFIG_USB_SERIAL_ZTE is not set
++# CONFIG_USB_SERIAL_SSU100 is not set
++# CONFIG_USB_SERIAL_QT2 is not set
++# CONFIG_USB_SERIAL_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_YUREX is not set
++# CONFIG_USB_EZUSB_FX2 is not set
++
++#
++# USB Physical Layer drivers
++#
++# CONFIG_USB_ISP1301 is not set
++# CONFIG_USB_RCAR_PHY is not set
++CONFIG_USB_GADGET=m
++# CONFIG_USB_GADGET_DEBUG is not set
++# CONFIG_USB_GADGET_DEBUG_FILES is not set
++# CONFIG_USB_GADGET_DEBUG_FS is not set
++CONFIG_USB_GADGET_VBUS_DRAW=2
++CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
++
++#
++# USB Peripheral Controller
++#
++# CONFIG_USB_R8A66597 is not set
++# CONFIG_USB_MV_UDC is not set
++# CONFIG_USB_M66592 is not set
++# CONFIG_USB_AMD5536UDC is not set
++# CONFIG_USB_NET2272 is not set
++# CONFIG_USB_NET2280 is not set
++# CONFIG_USB_GOKU is not set
++CONFIG_USB_EG20T=m
++# CONFIG_USB_DUMMY_HCD is not set
++CONFIG_USB_LIBCOMPOSITE=m
++CONFIG_USB_ZERO=m
++# CONFIG_USB_AUDIO is not set
++CONFIG_USB_ETH=m
++CONFIG_USB_ETH_RNDIS=y
++# CONFIG_USB_ETH_EEM is not set
++# CONFIG_USB_G_NCM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++CONFIG_USB_MASS_STORAGE=m
++CONFIG_USB_G_SERIAL=m
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_ACM_MS is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_DBGP is not set
++# CONFIG_USB_G_WEBCAM is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_NOP_USB_XCEIV is not set
++# CONFIG_UWB is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++# CONFIG_MMC_CLKGATE is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_MINORS=8
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=m
++CONFIG_MMC_SDHCI_PCI=m
++# CONFIG_MMC_RICOH_MMC is not set
++# CONFIG_MMC_SDHCI_ACPI is not set
++CONFIG_MMC_SDHCI_PLTFM=m
++# CONFIG_MMC_WBSD is not set
++# CONFIG_MMC_TIFM_SD is not set
++# CONFIG_MMC_CB710 is not set
++# CONFIG_MMC_VIA_SDMMC is not set
++# CONFIG_MMC_VUB300 is not set
++# CONFIG_MMC_USHC is not set
++# CONFIG_MEMSTICK is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=m
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_LM3530 is not set
++# CONFIG_LEDS_LM3642 is not set
++# CONFIG_LEDS_PCA9532 is not set
++# CONFIG_LEDS_GPIO is not set
++# CONFIG_LEDS_LP3944 is not set
++# CONFIG_LEDS_LP5521 is not set
++# CONFIG_LEDS_LP5523 is not set
++# CONFIG_LEDS_PCA955X is not set
++# CONFIG_LEDS_PCA9633 is not set
++# CONFIG_LEDS_DAC124S085 is not set
++# CONFIG_LEDS_BD2802 is not set
++# CONFIG_LEDS_INTEL_SS4200 is not set
++# CONFIG_LEDS_LT3593 is not set
++# CONFIG_LEDS_TCA6507 is not set
++# CONFIG_LEDS_LM355x is not set
++# CONFIG_LEDS_OT200 is not set
++# CONFIG_LEDS_BLINKM is not set
++CONFIG_LEDS_TRIGGERS=y
++
++#
++# LED Triggers
++#
++# CONFIG_LEDS_TRIGGER_TIMER is not set
++# CONFIG_LEDS_TRIGGER_ONESHOT is not set
++# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_CPU is not set
++# CONFIG_LEDS_TRIGGER_GPIO is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
++
++#
++# iptables trigger is under Netfilter config (LED target)
++#
++# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
++# CONFIG_ACCESSIBILITY is not set
++# CONFIG_INFINIBAND is not set
++# CONFIG_EDAC is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_DS3232 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_ISL12022 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8523 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++# CONFIG_RTC_DRV_EM3027 is not set
++# CONFIG_RTC_DRV_RV3029C2 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T93 is not set
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++
++#
++# Platform RTC drivers
++#
++CONFIG_RTC_DRV_CMOS=y
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++# CONFIG_RTC_DRV_DS2404 is not set
++
++#
++# on-CPU RTC drivers
++#
++CONFIG_DMADEVICES=y
++# CONFIG_DMADEVICES_DEBUG is not set
++
++#
++# DMA Devices
++#
++CONFIG_INTEL_MID_DMAC=m
++# CONFIG_INTEL_IOATDMA is not set
++# CONFIG_TIMB_DMA is not set
++# CONFIG_PCH_DMA is not set
++CONFIG_DMA_ENGINE=y
++
++#
++# DMA Clients
++#
++# CONFIG_NET_DMA is not set
++# CONFIG_ASYNC_TX_DMA is not set
++# CONFIG_DMATEST is not set
++# CONFIG_AUXDISPLAY is not set
++CONFIG_UIO=m
++# CONFIG_UIO_CIF is not set
++# CONFIG_UIO_PDRV is not set
++# CONFIG_UIO_PDRV_GENIRQ is not set
++# CONFIG_UIO_DMEM_GENIRQ is not set
++# CONFIG_UIO_AEC is not set
++# CONFIG_UIO_SERCOS3 is not set
++# CONFIG_UIO_PCI_GENERIC is not set
++# CONFIG_UIO_NETX is not set
++
++#
++# Virtio drivers
++#
++# CONFIG_VIRTIO_PCI is not set
++# CONFIG_VIRTIO_MMIO is not set
++
++#
++# Microsoft Hyper-V guest support
++#
++# CONFIG_HYPERV is not set
++CONFIG_STAGING=y
++# CONFIG_ET131X is not set
++# CONFIG_SLICOSS is not set
++# CONFIG_USBIP_CORE is not set
++# CONFIG_W35UND is not set
++# CONFIG_PRISM2_USB is not set
++# CONFIG_ECHO is not set
++# CONFIG_COMEDI is not set
++# CONFIG_ASUS_OLED is not set
++# CONFIG_R8187SE is not set
++# CONFIG_RTL8192U is not set
++# CONFIG_RTLLIB is not set
++# CONFIG_R8712U is not set
++# CONFIG_RTS5139 is not set
++# CONFIG_TRANZPORT is not set
++# CONFIG_LINE6_USB is not set
++# CONFIG_USB_SERIAL_QUATECH2 is not set
++# CONFIG_VT6655 is not set
++# CONFIG_VT6656 is not set
++# CONFIG_DX_SEP is not set
++
++#
++# IIO staging drivers
++#
++# CONFIG_IIO_SW_RING is not set
++
++#
++# Accelerometers
++#
++# CONFIG_ADIS16201 is not set
++# CONFIG_ADIS16203 is not set
++# CONFIG_ADIS16204 is not set
++# CONFIG_ADIS16209 is not set
++# CONFIG_ADIS16220 is not set
++# CONFIG_ADIS16240 is not set
++# CONFIG_KXSD9 is not set
++# CONFIG_LIS3L02DQ is not set
++# CONFIG_SCA3000 is not set
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7291 is not set
++# CONFIG_AD7606 is not set
++# CONFIG_AD799X is not set
++# CONFIG_AD7780 is not set
++# CONFIG_AD7816 is not set
++# CONFIG_AD7192 is not set
++# CONFIG_ADT7410 is not set
++# CONFIG_AD7280 is not set
++CONFIG_MAX78M6610_LMU=m
++
++#
++# Analog digital bi-direction converters
++#
++# CONFIG_ADT7316 is not set
++
++#
++# Capacitance to digital converters
++#
++# CONFIG_AD7150 is not set
++# CONFIG_AD7152 is not set
++# CONFIG_AD7746 is not set
++
++#
++# Direct Digital Synthesis
++#
++# CONFIG_AD5930 is not set
++# CONFIG_AD9832 is not set
++# CONFIG_AD9834 is not set
++# CONFIG_AD9850 is not set
++# CONFIG_AD9852 is not set
++# CONFIG_AD9910 is not set
++# CONFIG_AD9951 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16060 is not set
++# CONFIG_ADIS16080 is not set
++# CONFIG_ADIS16130 is not set
++# CONFIG_ADIS16260 is not set
++# CONFIG_ADXRS450 is not set
++
++#
++# Network Analyzer, Impedance Converters
++#
++# CONFIG_AD5933 is not set
++
++#
++# Inertial measurement units
++#
++# CONFIG_ADIS16400 is not set
++
++#
++# Light sensors
++#
++# CONFIG_SENSORS_ISL29018 is not set
++# CONFIG_SENSORS_ISL29028 is not set
++# CONFIG_SENSORS_TSL2563 is not set
++# CONFIG_TSL2583 is not set
++# CONFIG_TSL2x7x is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_SENSORS_AK8975 is not set
++# CONFIG_SENSORS_HMC5843 is not set
++
++#
++# Active energy metering IC
++#
++# CONFIG_ADE7753 is not set
++# CONFIG_ADE7754 is not set
++# CONFIG_ADE7758 is not set
++# CONFIG_ADE7759 is not set
++# CONFIG_ADE7854 is not set
++
++#
++# Resolver to digital converters
++#
++# CONFIG_AD2S90 is not set
++# CONFIG_AD2S1200 is not set
++# CONFIG_AD2S1210 is not set
++
++#
++# Triggers - standalone
++#
++# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
++# CONFIG_IIO_GPIO_TRIGGER is not set
++CONFIG_IIO_SYSFS_TRIGGER=m
++CONFIG_IIO_HRTIMER_TRIGGER=m
++# CONFIG_IIO_SIMPLE_DUMMY is not set
++# CONFIG_ZSMALLOC is not set
++# CONFIG_CRYSTALHD is not set
++# CONFIG_ACPI_QUICKSTART is not set
++# CONFIG_USB_ENESTORAGE is not set
++# CONFIG_BCM_WIMAX is not set
++# CONFIG_FT1000 is not set
++
++#
++# Speakup console speech
++#
++# CONFIG_SPEAKUP is not set
++# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
++# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
++# CONFIG_STAGING_MEDIA is not set
++
++#
++# Android
++#
++# CONFIG_ANDROID is not set
++# CONFIG_USB_WPAN_HCD is not set
++# CONFIG_WIMAX_GDM72XX is not set
++# CONFIG_CSR_WIFI is not set
++# CONFIG_NET_VENDOR_SILICOM is not set
++# CONFIG_CED1401 is not set
++# CONFIG_DGRP is not set
++# CONFIG_SB105X is not set
++CONFIG_X86_PLATFORM_DEVICES=y
++# CONFIG_ACERHDF is not set
++# CONFIG_ASUS_LAPTOP is not set
++# CONFIG_FUJITSU_TABLET is not set
++# CONFIG_AMILO_RFKILL is not set
++# CONFIG_HP_ACCEL is not set
++# CONFIG_SONY_LAPTOP is not set
++# CONFIG_THINKPAD_ACPI is not set
++# CONFIG_SENSORS_HDAPS is not set
++# CONFIG_INTEL_MENLOW is not set
++# CONFIG_ACPI_WMI is not set
++# CONFIG_TOPSTAR_LAPTOP is not set
++# CONFIG_TOSHIBA_BT_RFKILL is not set
++# CONFIG_ACPI_CMPC is not set
++CONFIG_INTEL_QRK_ESRAM=y
++CONFIG_INTEL_QRK_ECC_REFRESH_PERIOD=24
++CONFIG_INTEL_QRK_THERMAL=y
++CONFIG_INTEL_QRK_AUDIO_CTRL=m
++# CONFIG_INTEL_IPS is not set
++# CONFIG_IBM_RTL is not set
++# CONFIG_XO15_EBOOK is not set
++
++#
++# Hardware Spinlock drivers
++#
++CONFIG_CLKSRC_I8253=y
++CONFIG_CLKEVT_I8253=y
++CONFIG_CLKBLD_I8253=y
++# CONFIG_IOMMU_SUPPORT is not set
++
++#
++# Remoteproc drivers (EXPERIMENTAL)
++#
++# CONFIG_STE_MODEM_RPROC is not set
++
++#
++# Rpmsg drivers (EXPERIMENTAL)
++#
++# CONFIG_VIRT_DRIVERS is not set
++# CONFIG_PM_DEVFREQ is not set
++# CONFIG_EXTCON is not set
++# CONFIG_MEMORY is not set
++CONFIG_IIO=m
++CONFIG_IIO_BUFFER=y
++CONFIG_IIO_BUFFER_CB=y
++CONFIG_IIO_KFIFO_BUF=m
++CONFIG_IIO_TRIGGERED_BUFFER=m
++CONFIG_IIO_TRIGGER=y
++CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
++
++#
++# Accelerometers
++#
++CONFIG_IIO_LIS331DLH_INTEL_QRK=m
++
++#
++# Analog to digital converters
++#
++# CONFIG_AD7266 is not set
++CONFIG_AD7298=m
++# CONFIG_AD7791 is not set
++# CONFIG_AD7793 is not set
++# CONFIG_AD7476 is not set
++# CONFIG_AD7887 is not set
++# CONFIG_MAX1363 is not set
++# CONFIG_TI_ADC081C is not set
++
++#
++# Amplifiers
++#
++# CONFIG_AD8366 is not set
++
++#
++# Hid Sensor IIO Common
++#
++CONFIG_IIO_ST_SENSORS_I2C=m
++CONFIG_IIO_ST_SENSORS_SPI=m
++CONFIG_IIO_ST_SENSORS_CORE=m
++
++#
++# Digital to analog converters
++#
++# CONFIG_AD5064 is not set
++# CONFIG_AD5360 is not set
++# CONFIG_AD5380 is not set
++# CONFIG_AD5421 is not set
++# CONFIG_AD5624R_SPI is not set
++# CONFIG_AD5446 is not set
++# CONFIG_AD5449 is not set
++# CONFIG_AD5504 is not set
++# CONFIG_AD5755 is not set
++# CONFIG_AD5764 is not set
++# CONFIG_AD5791 is not set
++# CONFIG_AD5686 is not set
++# CONFIG_MAX517 is not set
++# CONFIG_MCP4725 is not set
++
++#
++# Frequency Synthesizers DDS/PLL
++#
++
++#
++# Clock Generator/Distribution
++#
++# CONFIG_AD9523 is not set
++
++#
++# Phase-Locked Loop (PLL) frequency synthesizers
++#
++# CONFIG_ADF4350 is not set
++
++#
++# Digital gyroscope sensors
++#
++# CONFIG_ADIS16136 is not set
++
++#
++# Inertial measurement units
++#
++# CONFIG_ADIS16480 is not set
++
++#
++# Light sensors
++#
++# CONFIG_ADJD_S311 is not set
++# CONFIG_VCNL4000 is not set
++
++#
++# Magnetometer sensors
++#
++# CONFIG_VME_BUS is not set
++CONFIG_PWM=y
++CONFIG_PWM_SYSFS=y
++# CONFIG_IPACK_BUS is not set
++
++#
++# Firmware Drivers
++#
++# CONFIG_EDD is not set
++CONFIG_FIRMWARE_MEMMAP=y
++CONFIG_EFI_VARS=m
++# CONFIG_DELL_RBU is not set
++# CONFIG_DCDBAS is not set
++CONFIG_DMIID=y
++CONFIG_DMI_SYSFS=y
++# CONFIG_ISCSI_IBFT_FIND is not set
++# CONFIG_GOOGLE_FIRMWARE is not set
++
++#
++# File systems
++#
++CONFIG_DCACHE_WORD_ACCESS=y
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
++CONFIG_EXT3_FS_XATTR=y
++CONFIG_EXT3_FS_POSIX_ACL=y
++CONFIG_EXT3_FS_SECURITY=y
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FS_MBCACHE=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FS_POSIX_ACL=y
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++CONFIG_DNOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_FANOTIFY is not set
++# CONFIG_QUOTA is not set
++# CONFIG_QUOTACTL is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++CONFIG_GENERIC_ACL=y
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++# CONFIG_MSDOS_FS is not set
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++CONFIG_TMPFS_POSIX_ACL=y
++CONFIG_TMPFS_XATTR=y
++CONFIG_HUGETLBFS=y
++CONFIG_HUGETLB_PAGE=y
++# CONFIG_CONFIGFS_FS is not set
++# CONFIG_MISC_FILESYSTEMS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++# CONFIG_NFS_FS is not set
++# CONFIG_NFSD is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=y
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_MAC_ROMAN is not set
++# CONFIG_NLS_MAC_CELTIC is not set
++# CONFIG_NLS_MAC_CENTEURO is not set
++# CONFIG_NLS_MAC_CROATIAN is not set
++# CONFIG_NLS_MAC_CYRILLIC is not set
++# CONFIG_NLS_MAC_GAELIC is not set
++# CONFIG_NLS_MAC_GREEK is not set
++# CONFIG_NLS_MAC_ICELAND is not set
++# CONFIG_NLS_MAC_INUIT is not set
++# CONFIG_NLS_MAC_ROMANIAN is not set
++# CONFIG_NLS_MAC_TURKISH is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Kernel hacking
++#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_PRINTK_TIME=y
++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=2048
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_READABLE_ASM is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++CONFIG_DEBUG_FS=y
++CONFIG_HEADERS_CHECK=y
++# CONFIG_DEBUG_SECTION_MISMATCH is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_LOCKUP_DETECTOR is not set
++# CONFIG_PANIC_ON_OOPS is not set
++CONFIG_PANIC_ON_OOPS_VALUE=0
++# CONFIG_DETECT_HUNG_TASK is not set
++# CONFIG_SCHED_DEBUG is not set
++# CONFIG_SCHEDSTATS is not set
++CONFIG_TIMER_STATS=y
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_SLUB_DEBUG_ON is not set
++# CONFIG_SLUB_STATS is not set
++CONFIG_HAVE_DEBUG_KMEMLEAK=y
++# CONFIG_DEBUG_KMEMLEAK is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_SPARSE_RCU_POINTER is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_ATOMIC_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_KOBJECT is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_VIRTUAL is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++CONFIG_DEBUG_MEMORY_INIT=y
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_TEST_LIST_SORT is not set
++# CONFIG_DEBUG_SG is not set
++# CONFIG_DEBUG_NOTIFIERS is not set
++# CONFIG_DEBUG_CREDENTIALS is not set
++CONFIG_ARCH_WANT_FRAME_POINTERS=y
++CONFIG_FRAME_POINTER=y
++# CONFIG_BOOT_PRINTK_DELAY is not set
++# CONFIG_RCU_TORTURE_TEST is not set
++# CONFIG_RCU_TRACE is not set
++# CONFIG_BACKTRACE_SELF_TEST is not set
++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
++# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
++# CONFIG_LKDTM is not set
++# CONFIG_NOTIFIER_ERROR_INJECTION is not set
++# CONFIG_FAULT_INJECTION is not set
++# CONFIG_LATENCYTOP is not set
++# CONFIG_DEBUG_PAGEALLOC is not set
++CONFIG_USER_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
++CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
++CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
++CONFIG_HAVE_DYNAMIC_FTRACE=y
++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
++CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
++CONFIG_HAVE_C_RECORDMCOUNT=y
++CONFIG_TRACING_SUPPORT=y
++# CONFIG_FTRACE is not set
++# CONFIG_RBTREE_TEST is not set
++# CONFIG_INTERVAL_TREE_TEST is not set
++# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
++# CONFIG_BUILD_DOCSRC is not set
++# CONFIG_DYNAMIC_DEBUG is not set
++# CONFIG_DMA_API_DEBUG is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_KGDB is not set
++CONFIG_HAVE_ARCH_KMEMCHECK=y
++# CONFIG_KMEMCHECK is not set
++# CONFIG_TEST_KSTRTOX is not set
++# CONFIG_STRICT_DEVMEM is not set
++CONFIG_X86_VERBOSE_BOOTUP=y
++CONFIG_EARLY_PRINTK=y
++# CONFIG_EARLY_PRINTK_DBGP is not set
++CONFIG_DEBUG_STACKOVERFLOW=y
++CONFIG_X86_PTDUMP=y
++CONFIG_DEBUG_RODATA=y
++# CONFIG_DEBUG_RODATA_TEST is not set
++CONFIG_DEBUG_SET_MODULE_RONX=y
++# CONFIG_DEBUG_NX_TEST is not set
++# CONFIG_DOUBLEFAULT is not set
++# CONFIG_IOMMU_STRESS is not set
++CONFIG_HAVE_MMIOTRACE_SUPPORT=y
++CONFIG_IO_DELAY_TYPE_0X80=0
++CONFIG_IO_DELAY_TYPE_0XED=1
++CONFIG_IO_DELAY_TYPE_UDELAY=2
++CONFIG_IO_DELAY_TYPE_NONE=3
++CONFIG_IO_DELAY_0X80=y
++# CONFIG_IO_DELAY_0XED is not set
++# CONFIG_IO_DELAY_UDELAY is not set
++# CONFIG_IO_DELAY_NONE is not set
++CONFIG_DEFAULT_IO_DELAY_TYPE=0
++CONFIG_DEBUG_BOOT_PARAMS=y
++# CONFIG_CPA_DEBUG is not set
++CONFIG_OPTIMIZE_INLINING=y
++# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
++# CONFIG_DEBUG_NMI_SELFTEST is not set
++
++#
++# Security options
++#
++CONFIG_KEYS=y
++# CONFIG_ENCRYPTED_KEYS is not set
++CONFIG_KEYS_DEBUG_PROC_KEYS=y
++# CONFIG_SECURITY_DMESG_RESTRICT is not set
++CONFIG_SECURITY=y
++# CONFIG_SECURITYFS is not set
++CONFIG_SECURITY_NETWORK=y
++# CONFIG_SECURITY_NETWORK_XFRM is not set
++# CONFIG_SECURITY_PATH is not set
++# CONFIG_SECURITY_SMACK is not set
++# CONFIG_SECURITY_TOMOYO is not set
++# CONFIG_SECURITY_APPARMOR is not set
++# CONFIG_SECURITY_YAMA is not set
++# CONFIG_IMA is not set
++# CONFIG_EVM is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++CONFIG_CRYPTO_AEAD2=y
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_BLKCIPHER2=y
++CONFIG_CRYPTO_HASH=y
++CONFIG_CRYPTO_HASH2=y
++CONFIG_CRYPTO_RNG=m
++CONFIG_CRYPTO_RNG2=y
++CONFIG_CRYPTO_PCOMP2=y
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_MANAGER2=y
++# CONFIG_CRYPTO_USER is not set
++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++CONFIG_CRYPTO_WORKQUEUE=y
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++CONFIG_CRYPTO_CRC32C=y
++# CONFIG_CRYPTO_CRC32C_INTEL is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++CONFIG_CRYPTO_SHA256=m
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=y
++# CONFIG_CRYPTO_AES_586 is not set
++# CONFIG_CRYPTO_AES_NI_INTEL is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SALSA20_586 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_TWOFISH_586 is not set
++
++#
++# Compression
++#
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_ZLIB is not set
++# CONFIG_CRYPTO_LZO is not set
++
++#
++# Random Number Generation
++#
++CONFIG_CRYPTO_ANSI_CPRNG=m
++# CONFIG_CRYPTO_USER_API_HASH is not set
++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
++CONFIG_CRYPTO_HW=y
++# CONFIG_CRYPTO_DEV_PADLOCK is not set
++# CONFIG_CRYPTO_DEV_GEODE is not set
++# CONFIG_ASYMMETRIC_KEY_TYPE is not set
++CONFIG_HAVE_KVM=y
++# CONFIG_VIRTUALIZATION is not set
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_GENERIC_STRNCPY_FROM_USER=y
++CONFIG_GENERIC_STRNLEN_USER=y
++CONFIG_GENERIC_FIND_FIRST_BIT=y
++CONFIG_GENERIC_PCI_IOMAP=y
++CONFIG_GENERIC_IOMAP=y
++CONFIG_GENERIC_IO=y
++CONFIG_PERCPU_RWSEM=y
++CONFIG_CRC_CCITT=m
++CONFIG_CRC16=y
++CONFIG_CRC_T10DIF=y
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC32_SELFTEST is not set
++CONFIG_CRC32_SLICEBY8=y
++# CONFIG_CRC32_SLICEBY4 is not set
++# CONFIG_CRC32_SARWATE is not set
++# CONFIG_CRC32_BIT is not set
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++# CONFIG_CRC8 is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=m
++# CONFIG_XZ_DEC is not set
++# CONFIG_XZ_DEC_BCJ is not set
++CONFIG_DECOMPRESS_GZIP=y
++CONFIG_DECOMPRESS_BZIP2=y
++CONFIG_DECOMPRESS_LZMA=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_DQL=y
++CONFIG_NLATTR=y
++CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
++CONFIG_AVERAGE=y
++# CONFIG_CORDIC is not set
++# CONFIG_DDR is not set
+--
+1.7.4.1
+
diff --git a/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch b/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch
new file mode 100644
index 0000000..21f2d7f
--- /dev/null
+++ b/recipes-kernel/linux/files/0007-Quark-Platform-Code-quark.patch
@@ -0,0 +1,6501 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Quark Team <noreply@intel.com>
+Date: Wed, 26 Feb 2014 14:40:08 +0000
+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(-)
+ 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
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_audio_ctrl.h
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_board_data.c
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_esram.c
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_esram.h
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_esram_test.c
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_esram_test.h
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_imr.c
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_imr.h
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_imr_kernel.c
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_imr_test.c
+ create mode 100644 drivers/platform/x86/quark/intel_qrk_plat_clanton_hill.c
+ 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_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
+ create mode 100644 include/linux/intel_qrk_sb.h
+ create mode 100644 include/linux/platform_data/quark.h
+
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index c86bae8..6def5f6 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -672,6 +672,10 @@ config INTEL_MFLD_THERMAL
+ Say Y here to enable thermal driver support for the Intel Medfield
+ platform.
+
++if INTEL_QUARK_X1000_SOC
++source "drivers/platform/x86/quark/Kconfig"
++endif
++
+ config INTEL_IPS
+ tristate "Intel Intelligent Power Sharing"
+ depends on ACPI
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index bf7e4f9..fce76ef 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -50,3 +50,4 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
+ obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
+ obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
+ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += quark/
+diff --git a/drivers/platform/x86/quark/Kconfig b/drivers/platform/x86/quark/Kconfig
+new file mode 100644
+index 0000000..0e2c722
+--- /dev/null
++++ b/drivers/platform/x86/quark/Kconfig
+@@ -0,0 +1,41 @@
++config INTEL_QRK_ESRAM
++ bool "eSRAM - embedded SRAM driver for Intel Quark platform"
++ depends on INTEL_QUARK_X1000_SOC && PM
++ select KALLSYMS
++ select CRC16
++ help
++ Say Y here to enable eSRAM overlay and software-initiated ECC
++ updates. eSRAM overlaying allows for code/data structures to be
++ mapped into eSRAM thus providing far faster access to code/data
++ than ordinary DRAM. Slower than cache RAM faster than DRAM.
++
++config INTEL_QRK_ECC_REFRESH_PERIOD
++ int "Choose eSRAM ECC coverage period"
++ depends on INTEL_QRK_ESRAM
++ default 24
++ help
++ Select the period over which *RAM ECC codes should be refreshed.
++ IA Core will periodically enable disabled eSRAM pages to ensure all of
++ disabled eSRAM pages are 'address walked' in this period. A logical
++ component within the silicon on Quark will ensure DRAM (and
++ overlayed eSRAM) pages by extension are similarly updated over the
++ same period. This variable controlls how long a time this address
++ walking algorithm should take. For a noisy environment like a
++ sub-station or a satellite update frequently. For less noisy
++ environments this value should be lower. Default 24 hours is right for
++ most people. Set to zero to disable - this is NOT recommended. Max 48
++ hours.
++
++config INTEL_QRK_THERMAL
++ bool "Thermal driver for Intel Quark platform"
++ depends on INTEL_QUARK_X1000_SOC
++ help
++ Say Y here to enable Quark's Thermal driver plus the MSI's
++ that can be hooked from the thermal sub-system
++
++config INTEL_QRK_AUDIO_CTRL
++ tristate "Audio sub-system control driver for Intel Quark platform"
++ depends on INTEL_QUARK_X1000_SOC
++ help
++ Say Y here to enable Quark's audio control driver
++
+diff --git a/drivers/platform/x86/quark/Makefile b/drivers/platform/x86/quark/Makefile
+new file mode 100644
+index 0000000..0a03469
+--- /dev/null
++++ b/drivers/platform/x86/quark/Makefile
+@@ -0,0 +1,14 @@
++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_sb.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_imr.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_imr_kernel.o
++obj-$(CONFIG_INTEL_QRK_ESRAM) += intel_qrk_esram.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_imr_test.o
++obj-$(CONFIG_INTEL_QRK_ESRAM) += intel_qrk_esram_test.o
++obj-$(CONFIG_INTEL_QRK_THERMAL) += intel_qrk_thermal.o
++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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_audio_ctrl.c
+@@ -0,0 +1,514 @@
++/*
++ * 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.
++ *
++ * 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
++ *
++ * The Intel Clanton Hill platform hardware design includes an audio subsystem
++ * with a number of interconnected audio interfaces. This driver enables
++ * applications to choose which audio connections to enable for various
++ * application use cases. The interconnections are selectable using GPIO output
++ * pins on the CPU. This driver is also responsible for configuring a Maxim
++ * 9867 audio codec, a component of this audio subsystem, connected to the CPU
++ * via I2C.
++ */
++
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/gpio.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <uapi/linux/ioctl.h>
++#include <linux/mutex.h>
++#include <linux/sysfs.h>
++
++#include "intel_qrk_audio_ctrl.h"
++
++#define DRIVER_NAME "intel_qrk_audio_ctrl"
++
++/*
++ * GPIO numbers to use for switching audio paths
++ */
++#define GPIO_AUDIO_S0 11
++#define GPIO_AUDIO_S1 12
++#define GPIO_AUDIO_S2 13
++
++#define GPIO_AUDIO_DEFAULT (INTEL_QRK_AUDIO_MODE_SPKR_MIC)
++
++/**
++ * struct intel_qrk_audio_ctrl_data
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_qrk_audio_ctrl_priv {
++
++ /* i2c device descriptor for read/write access to MAX9867 registers */
++ struct i2c_client *max9867_i2c;
++
++ /* Char dev to provide user-space ioctl interface for audio control */
++ struct cdev cdev;
++ dev_t cdev_no;
++ struct class *cl;
++
++ /* Mutex to protect against concurrent access to the ioctl() handler */
++ struct mutex lock;
++
++ /* Current GPIO switch value */
++ unsigned char gpio_val;
++};
++
++static int
++intel_qrk_audio_ctrl_open(struct inode *inode, struct file *filp)
++{
++ struct intel_qrk_audio_ctrl_priv *priv;
++
++ priv = container_of(inode->i_cdev,
++ struct intel_qrk_audio_ctrl_priv,
++ cdev);
++ filp->private_data = priv;
++
++ return 0;
++}
++
++static int
++intel_qrk_audio_ctrl_release(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++/*
++ * Logic truth table for AUDIO_S[0-3] outputs, illustrating which paths are
++ * connected between audio interfaces A, B, C. Each audio interface has one
++ * effective input (I) port and one effective output (O) port
++ *
++ * A = USB Codec (to Quark CPU)
++ * B = Spkr/Mic (to car audio system)
++ * C = I2S Codec (to Telit HE910)
++ *
++ * PATH examples:
++ * AO-CO: A-Output connected to C-Output
++ * BI-AI: B-Input connected to A-Input
++ *
++ * NOTE: Assume a CI-AI connection is available in ALL cases (sometimes unused)
++ *
++ * S2 S1 S0 PATHS USE CASE
++ * -- -- -- ----------------- -------------------------------------------------
++ * 0 0 0 AO-CO BT Headset call
++ * 0 0 1 AO-BO Analog Driver Alerts (CI unused)
++ * 0 1 0 AO-CO,BI-AI XX Unused/invalid (BI *and* CI connected to AI)
++ * 0 1 1 AO-BO,BI-AI Archival Voice Record/Playback (or Driver Alerts)
++ * 1 0 0 AO-CO,BI-CO XX Unused/invalid (A0 *and* BI connected to CO)
++ * 1 0 1 AO-BO,BI-CO Analog hands-free call
++ * 1 1 0 AO-CO,BI-AI,BI-CO XX Unused/invalid (BI connected to AI *and* CO)
++ * 1 1 1 AO-BO,BI-AI,BI-CO XX Unused/invalid (BI connected to AI *and* CO)
++ *
++ *
++ * Mapping to IOCTLs (using more intuitive naming on the API):
++ *
++ * PATHS IOCTL
++ * --------------- -------------------------------------------------------------
++ * AO-CO INTEL_QRK_AUDIO_MODE_GSM_ONLY
++ * AO-BO INTEL_QRK_AUDIO_MODE_SPKR_ONLY
++ * AO-BO,BI-AI INTEL_QRK_AUDIO_MODE_SPKR_MIC
++ * AO-BO,BI-CO INTEL_QRK_AUDIO_MODE_GSM_SPKR_MIC
++ */
++
++static int
++intel_qrk_audio_ctrl_gpio_update(struct intel_qrk_audio_ctrl_priv *priv)
++{
++ int ret = 0;
++ struct gpio audio_sw_gpios[] = {
++ {
++ GPIO_AUDIO_S2,
++ GPIOF_OUT_INIT_LOW,
++ "audio_s2"
++ },
++ {
++ GPIO_AUDIO_S1,
++ GPIOF_OUT_INIT_LOW,
++ "audio_s1"
++ },
++ {
++ GPIO_AUDIO_S0,
++ GPIOF_OUT_INIT_LOW,
++ "audio_s0"
++ }
++ };
++
++ /*
++ * Update the Audio Switch GPIO outputs according to the user selection
++ */
++ ret = gpio_request_array(audio_sw_gpios,
++ ARRAY_SIZE(audio_sw_gpios));
++ if (ret) {
++ pr_err("%s: Failed to allocate audio control GPIO pins\n",
++ __func__);
++ return ret;
++ }
++
++ gpio_set_value(GPIO_AUDIO_S2, (priv->gpio_val >> 2) & 0x1);
++ gpio_set_value(GPIO_AUDIO_S1, (priv->gpio_val >> 1) & 0x1);
++ gpio_set_value(GPIO_AUDIO_S0, (priv->gpio_val >> 0) & 0x1);
++
++ gpio_free_array(audio_sw_gpios,
++ ARRAY_SIZE(audio_sw_gpios));
++
++ return 0;
++}
++
++static long
++intel_qrk_audio_ctrl_ioctl(struct file *filp,
++ unsigned int cmd,
++ unsigned long arg)
++{
++ struct intel_qrk_audio_ctrl_priv *priv = filp->private_data;
++ int ret = 0;
++
++ ret = mutex_lock_interruptible(&priv->lock);
++ if (ret)
++ return ret;
++
++ switch (cmd) {
++ case INTEL_QRK_AUDIO_MODE_IOC_GSM_ONLY:
++ case INTEL_QRK_AUDIO_MODE_IOC_SPKR_ONLY:
++ case INTEL_QRK_AUDIO_MODE_IOC_SPKR_MIC:
++ case INTEL_QRK_AUDIO_MODE_IOC_GSM_SPKR_MIC:
++ break;
++ default:
++ ret = -EINVAL;
++ goto exit;
++ }
++
++ priv->gpio_val = _IOC_NR(cmd) & 0x7;
++ ret = intel_qrk_audio_ctrl_gpio_update(priv);
++exit:
++ mutex_unlock(&priv->lock);
++ return ret;
++}
++
++static const struct file_operations intel_qrk_audio_ctrl_fops = {
++ .owner = THIS_MODULE,
++ .open = intel_qrk_audio_ctrl_open,
++ .release = intel_qrk_audio_ctrl_release,
++ .unlocked_ioctl = intel_qrk_audio_ctrl_ioctl
++};
++
++static int
++intel_qrk_audio_ctrl_chrdev_init(struct intel_qrk_audio_ctrl_priv *priv)
++{
++ /* Register a character dev interface (with ioctls)
++ * to allow control of the audio subsystem switch
++ */
++ int ret;
++ struct device *dev;
++
++ ret = alloc_chrdev_region(&priv->cdev_no, 0, 1,
++ "intel_qrk_audio_ctrl");
++ if (ret) {
++ pr_err("Failed to alloc chrdev: %d", ret);
++ return ret;
++ }
++
++ cdev_init(&priv->cdev, &intel_qrk_audio_ctrl_fops);
++
++ ret = cdev_add(&priv->cdev, priv->cdev_no, 1);
++ if (ret) {
++ pr_err("Failed to add cdev: %d", ret);
++ unregister_chrdev_region(priv->cdev_no, 1);
++ return ret;
++ }
++
++ priv->cl = class_create(THIS_MODULE, "char");
++ if (IS_ERR(priv->cl)) {
++ pr_err("Failed to create device class: %ld",
++ PTR_ERR(priv->cl));
++ cdev_del(&priv->cdev);
++ unregister_chrdev_region(priv->cdev_no, 1);
++ return PTR_ERR(priv->cl);
++ }
++
++ dev = device_create(priv->cl, NULL, priv->cdev_no, NULL,
++ "intel_qrk_audio_ctrl");
++ if (IS_ERR(dev)) {
++ pr_err("Failed to create device: %ld",
++ PTR_ERR(priv->cl));
++ class_destroy(priv->cl);
++ cdev_del(&priv->cdev);
++ unregister_chrdev_region(priv->cdev_no, 1);
++ return PTR_ERR(dev);
++ }
++
++ return 0;
++}
++
++static int
++intel_qrk_audio_ctrl_chrdev_remove(struct intel_qrk_audio_ctrl_priv *priv)
++{
++ device_destroy(priv->cl, priv->cdev_no);
++ class_destroy(priv->cl);
++ cdev_del(&priv->cdev);
++ unregister_chrdev_region(priv->cdev_no, 1);
++
++ return 0;
++}
++
++
++ssize_t intel_qrk_audio_ctrl_sysfs_show_mode(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct intel_qrk_audio_ctrl_priv *priv = dev_get_drvdata(dev);
++ int ret;
++ char *mode;
++
++ ret = mutex_lock_interruptible(&priv->lock);
++ if (ret)
++ return ret;
++
++ switch (priv->gpio_val) {
++ case INTEL_QRK_AUDIO_MODE_GSM_ONLY:
++ mode = "gsm";
++ break;
++ case INTEL_QRK_AUDIO_MODE_SPKR_ONLY:
++ mode = "spkr";
++ break;
++ case INTEL_QRK_AUDIO_MODE_SPKR_MIC:
++ mode = "spkr_mic";
++ break;
++ case INTEL_QRK_AUDIO_MODE_GSM_SPKR_MIC:
++ mode = "gsm_spkr_mic";
++ break;
++ default:
++ ret = -EINVAL;
++ goto exit;
++ }
++
++ ret = scnprintf(buf, PAGE_SIZE, "%s\n", mode);
++
++exit:
++ mutex_unlock(&priv->lock);
++ return ret;
++}
++
++ssize_t intel_qrk_audio_ctrl_sysfs_store_mode(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct intel_qrk_audio_ctrl_priv *priv = dev_get_drvdata(dev);
++ char mode[16];
++ unsigned char gpio_val;
++ int ret = count;
++
++ sscanf(buf, "%15s", mode);
++
++ if (!strcmp(mode, "gsm"))
++ gpio_val = INTEL_QRK_AUDIO_MODE_GSM_ONLY;
++ else if (!strcmp(mode, "spkr"))
++ gpio_val = INTEL_QRK_AUDIO_MODE_SPKR_ONLY;
++ else if (!strcmp(mode, "spkr_mic"))
++ gpio_val = INTEL_QRK_AUDIO_MODE_SPKR_MIC;
++ else if (!strcmp(mode, "gsm_spkr_mic"))
++ gpio_val = INTEL_QRK_AUDIO_MODE_GSM_SPKR_MIC;
++ else
++ return -EINVAL;
++
++ ret = mutex_lock_interruptible(&priv->lock);
++ if (ret)
++ return ret;
++
++ priv->gpio_val = gpio_val;
++ ret = intel_qrk_audio_ctrl_gpio_update(priv);
++ if (ret)
++ goto exit;
++
++ ret = count;
++
++exit:
++ mutex_unlock(&priv->lock);
++
++ return ret;
++}
++
++/* Sysfs attribute descriptor (for alternative user-space interface) */
++static DEVICE_ATTR(audio_switch_mode, S_IWUSR | S_IRUGO,
++ intel_qrk_audio_ctrl_sysfs_show_mode,
++ intel_qrk_audio_ctrl_sysfs_store_mode);
++
++/******************************************************************************
++ * Module hooks
++ ******************************************************************************/
++
++static int
++intel_qrk_max9867_init(struct i2c_client *client)
++{
++ int ret;
++
++ /* MAX9867 register configuration, from Telit HE910 DVI app-note */
++
++ u8 reg_cfg_seq1[] = {
++ 0x04, /* Starting register address, followed by data */
++ 0x00, /* 0x04 Interrupt Enable */
++ 0x10, /* 0x05 System Clock */
++ 0x90, /* 0x06 Audio Clock High */
++ 0x00, /* 0x07 Audio Clock Low */
++ 0x10, /* 0x08 Interface 1a */
++ 0x0A, /* 0x09 Interface 1d */
++ 0x33, /* 0x0A Codec Filters */
++ 0x00, /* 0x0B DAC Gain/Sidetone */
++ 0x00, /* 0x0C DAC Level */
++ 0x33, /* 0x0D ADC Level */
++ 0x4C, /* 0x0E Left Line Input Level */
++ 0x4C, /* 0x0F Right Line Input Level */
++ 0x00, /* 0x10 Left Volume Control */
++ 0x00, /* 0x11 Right Volume Control */
++ 0x14, /* 0x12 Left Mic Gain */
++ 0x14, /* 0x13 Right Mic Gain */
++ /* Configuration */
++ 0xA0, /* 0x14 Input */
++ 0x00, /* 0x15 Microphone */
++ 0x65 /* 0x16 Mode */
++ };
++
++ u8 reg_cfg_seq2[] = {
++ 0x17, /* Starting register address, followed by data */
++ 0xEF /* 0x17 System Shutdown */
++ };
++
++ ret = i2c_master_send(client,
++ reg_cfg_seq1, sizeof(reg_cfg_seq1));
++ if (ret != sizeof(reg_cfg_seq1)) {
++ pr_err("Failed to write MAX9867 config registers (set 1/2)");
++ return -EIO;
++ }
++
++ ret = i2c_master_send(client,
++ reg_cfg_seq2, sizeof(reg_cfg_seq2));
++ if (ret != sizeof(reg_cfg_seq2)) {
++ pr_err("Failed to write MAX9867 config registers (set 2/2)");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int
++intel_qrk_max9867_get_chip_rev(struct i2c_client *client)
++{
++ struct i2c_msg msg[2];
++ u8 data[2];
++ int ret;
++
++ data[0] = 0xFF; /* Chip-revision register address = 0xFF */
++ msg[0].addr = client->addr;
++ msg[0].flags = 0;
++ msg[0].buf = &data[0];
++ msg[0].len = 1;
++
++ msg[1].addr = client->addr;
++ msg[1].flags = I2C_M_RD;
++ msg[1].buf = &data[1];
++ msg[1].len = 1;
++
++ ret = i2c_transfer(client->adapter, &msg[0], 2);
++ return (ret == 2) ? data[1] : -EIO;
++}
++
++static int intel_qrk_max9867_i2c_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct intel_qrk_audio_ctrl_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv),
++ GFP_KERNEL);
++ if (priv == NULL)
++ return -ENOMEM;
++
++ i2c_set_clientdata(client, priv);
++
++ priv->max9867_i2c = client;
++ mutex_init(&priv->lock);
++
++ ret = intel_qrk_max9867_get_chip_rev(client);
++ if (ret >= 0)
++ pr_info("%s: Detected MAX9867 chip revision 0x%02X\n",
++ __func__, ret);
++ else {
++ pr_err("%s: Failed to read MAX9867 chip revision\n", __func__);
++ goto exit;
++ }
++
++ ret = intel_qrk_max9867_init(client);
++ if (ret)
++ goto exit;
++
++ priv->gpio_val = GPIO_AUDIO_DEFAULT;
++ ret = intel_qrk_audio_ctrl_gpio_update(priv);
++ if (ret)
++ goto exit;
++
++ /* Create a char dev interface, providing an ioctl config option */
++ ret = intel_qrk_audio_ctrl_chrdev_init(priv);
++ if (ret)
++ goto exit;
++
++ /* Also create a sysfs interface, providing a cmd line config option */
++ ret = sysfs_create_file(&client->dev.kobj,
++ &dev_attr_audio_switch_mode.attr);
++
++exit:
++ return ret;
++}
++
++static int intel_qrk_max9867_i2c_remove(struct i2c_client *client)
++{
++ struct intel_qrk_audio_ctrl_priv *priv = i2c_get_clientdata(client);
++
++ intel_qrk_audio_ctrl_chrdev_remove(priv);
++
++ sysfs_remove_file(&client->dev.kobj, &dev_attr_audio_switch_mode.attr);
++
++ return 0;
++}
++
++static const struct i2c_device_id intel_qrk_max9867_i2c_id[] = {
++ {"intel-qrk-max9867", 0},
++ {}
++};
++MODULE_DEVICE_TABLE(i2c, intel_qrk_max9867_i2c_id);
++
++/* i2c codec control layer */
++static struct i2c_driver intel_qrk_audio_ctrl_i2c_driver = {
++ .driver = {
++ .name = "intel_qrk_audio_ctrl",
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_max9867_i2c_probe,
++ .remove = intel_qrk_max9867_i2c_remove,
++ .id_table = intel_qrk_max9867_i2c_id,
++};
++
++module_i2c_driver(intel_qrk_audio_ctrl_i2c_driver);
++
++MODULE_AUTHOR("Dan O'Donovan <dan@emutex.com>");
++MODULE_DESCRIPTION("Intel Quark platform audio control driver");
++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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_audio_ctrl.h
+@@ -0,0 +1,45 @@
++/*
++ * 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.
++ *
++ * 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
++ *
++ * See intel_qrk_audio_ctrl.c for a detailed description
++ *
++ */
++
++#ifndef __INTEL_QRK_AUDIO_CTRL_H__
++#define __INTEL_QRK_AUDIO_CTRL_H__
++
++#include <linux/module.h>
++
++#define INTEL_QRK_AUDIO_MODE_GSM_ONLY 0x0
++#define INTEL_QRK_AUDIO_MODE_SPKR_ONLY 0x1
++#define INTEL_QRK_AUDIO_MODE_SPKR_MIC 0x3
++#define INTEL_QRK_AUDIO_MODE_GSM_SPKR_MIC 0x5
++
++#define INTEL_QRK_AUDIO_MODE_IOC_GSM_ONLY \
++ _IO('x', INTEL_QRK_AUDIO_MODE_GSM_ONLY)
++#define INTEL_QRK_AUDIO_MODE_IOC_SPKR_ONLY \
++ _IO('x', INTEL_QRK_AUDIO_MODE_SPKR_ONLY)
++#define INTEL_QRK_AUDIO_MODE_IOC_SPKR_MIC \
++ _IO('x', INTEL_QRK_AUDIO_MODE_SPKR_MIC)
++#define INTEL_QRK_AUDIO_MODE_IOC_GSM_SPKR_MIC \
++ _IO('x', INTEL_QRK_AUDIO_MODE_GSM_SPKR_MIC)
++
++#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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_board_data.c
+@@ -0,0 +1,260 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark Legacy Platform Data accessor layer
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <asm/io.h>
++#include <linux/dmi.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++
++#define DRIVER_NAME "board_data"
++#define PFX "MFH: "
++#define SPIFLASH_BASEADDR 0xFFF00000
++#define MFH_OFFSET 0x00008000
++#define PLATFORM_DATA_OFFSET 0x00010000
++#define MTD_PART_OFFSET 0x00050000
++#define MTD_PART_LEN 0x00040000
++#define MFH_PADDING 0x1E8
++#define MFH_MAGIC 0x5F4D4648
++#define FLASH_SIZE 0x00400000
++
++/* MFH types supported @ version #1 */
++#define MFH_ITEM_FW_STAGE1 0x00000000
++#define MFH_ITEM_FW_STAGE1_SIGNED 0x00000001
++#define MFH_ITEM_FW_STAGE2 0x00000003
++#define MFH_ITEM_FW_STAGE2_SIGNED 0x00000004
++#define MFH_ITEM_FW_STAGE2_CONFIG 0x00000005
++#define MFH_ITEM_FW_STAGE2_CONFIG_SIGNED 0x00000006
++#define MFH_ITEM_FW_PARAMS 0x00000007
++#define MFH_ITEM_FW_RECOVERY 0x00000008
++#define MFH_ITEM_FW_RECOVERY_SIGNED 0x00000009
++#define MFH_ITEM_BOOTLOADER 0x0000000B
++#define MFH_ITEM_BOOTLOADER_SIGNED 0x0000000C
++#define MFH_ITEM_BOOTLOADER_CONFIG 0x0000000D
++#define MFH_ITEM_BOOTLOADER_CONFIG_SIGNED 0x0000000E
++#define MFH_ITEM_KERNEL 0x00000010
++#define MFH_ITEM_KERNEL_SIGNED 0x00000011
++#define MFH_ITEM_RAMDISK 0x00000012
++#define MFH_ITEM_RAMDISK_SIGNED 0x00000013
++#define MFH_ITEM_LOADABLE_PROGRAM 0x00000015
++#define MFH_ITEM_LOADABLE_PROGRAM_SIGNED 0x00000016
++#define MFH_ITEM_BUILD_INFO 0x00000018
++#define MFH_ITEM_VERSION 0x00000019
++
++struct intel_qrk_mfh {
++ u32 id;
++ u32 ver;
++ u32 flags;
++ u32 next_block;
++ u32 item_count;
++ u32 boot_priority_list;
++ u8 padding[MFH_PADDING];
++};
++
++struct intel_qrk_mfh_item {
++ u32 type;
++ u32 addr;
++ u32 len;
++ u32 res0;
++};
++
++struct kobject * board_data_kobj;
++EXPORT_SYMBOL_GPL(board_data_kobj);
++
++static long unsigned int flash_version_data;
++static ssize_t flash_version_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, 12, "%#010lx\n", flash_version_data);
++}
++
++static struct kobj_attribute flash_version_attr =
++ __ATTR(flash_version, 0644, flash_version_show, NULL);
++
++extern int intel_qrk_plat_probe(struct resource * pres);
++
++#define DEFAULT_BOARD "Galileo"
++
++static struct platform_device bsp_data [] = {
++ {
++ .name = "QuarkEmulation",
++ .id = -1,
++ },
++ {
++ .name = "ClantonPeakSVP",
++ .id = -1,
++ },
++ {
++ .name = "KipsBay",
++ .id = -1,
++ },
++ {
++ .name = "CrossHill",
++ .id = -1,
++ },
++ {
++ .name = "ClantonHill",
++ .id = -1,
++ },
++ {
++ .name = "Galileo",
++ .id = -1,
++ },
++
++};
++
++/**
++ * add_firmware_sysfs_entry
++ *
++ * Add an entry in sysfs consistent with Galileo IDE's expected location
++ * covers current software versions and legacy code < Intel Galileo BIOS 0.9.0
++ *
++ */
++static int add_firmware_sysfs_entry(const char * board_name)
++{
++ extern struct kobject * firmware_kobj;
++
++ pr_info("Intel Quark Board %s Firmware Version %#010lx\n",
++ board_name, flash_version_data);
++
++ /* board_data_kobj subordinate of firmware @ /sys/firmware/board_data */
++ board_data_kobj = kobject_create_and_add("board_data", firmware_kobj);
++ if (!board_data_kobj) {
++ pr_err(PFX"kset create error\n");
++ return -ENODEV;
++ }
++ return sysfs_create_file(board_data_kobj, &flash_version_attr.attr);
++}
++
++/**
++ * intel_qrk_board_data_init_legacy
++ *
++ * Module entry point for older BIOS versions
++ * Allows more recent kernels to boot on Galileo boards with BIOS before release
++ * 0.9.0
++ */
++static int __init intel_qrk_board_data_init_legacy(void)
++{
++ struct intel_qrk_mfh __iomem * mfh;
++ struct intel_qrk_mfh_item __iomem * item;
++ struct platform_device * pdev;
++ u32 i;
++ char * board_name = NULL;
++ void __iomem * spi_data;
++ int ret = 0;
++
++ spi_data = ioremap(SPIFLASH_BASEADDR, FLASH_SIZE);
++ if (!spi_data)
++ return -ENODEV;
++
++ /* get mfh and first item pointer */
++ mfh = spi_data + MFH_OFFSET;
++ if (mfh->id != MFH_MAGIC){
++ pr_err(PFX"Bad MFH magic want 0x%08x found 0x%08x @ 0x%p\n",
++ MFH_MAGIC, mfh->id, &mfh->id);
++ return -ENODEV;
++ }
++
++ pr_info(PFX"Booting on an old BIOS assuming %s board\n", DEFAULT_BOARD);
++ pr_info(PFX"mfh @ 0x%p: id 0x%08lx ver 0x%08lx entries 0x%08lx\n",
++ mfh, (unsigned long)mfh->id, (unsigned long)mfh->ver,
++ (unsigned long)mfh->item_count);
++ item = (struct intel_qrk_mfh_item __iomem *)
++ &mfh->padding [sizeof(u32) * mfh->boot_priority_list];
++
++ /* Register a default board */
++ for (i = 0; i < sizeof(bsp_data)/sizeof(struct platform_device); i++){
++ if (!strcmp(bsp_data[i].name, DEFAULT_BOARD)){
++ board_name = (char*)bsp_data[i].name;
++ platform_device_register(&bsp_data[i]);
++ }
++ }
++
++ /* Register flash regions as seperate platform devices */
++ for (i = 0; i < mfh->item_count; i++, item++){
++ pdev = NULL;
++
++ switch (item->type){
++ case MFH_ITEM_VERSION:
++ flash_version_data = item->res0;
++ ret = add_firmware_sysfs_entry(board_name);
++ break;
++ default:
++ break;
++ }
++ }
++ iounmap(spi_data);
++ return ret;
++}
++
++/**
++ * intel_qrk_board_data_init_legacy
++ *
++ * Module entry point for older BIOS versions
++ */
++static int __init intel_qrk_board_data_init(void)
++{
++ bool found = false;
++ const char * bios_version = dmi_get_system_info(DMI_BIOS_VERSION);
++ const char * board_name = dmi_get_system_info(DMI_BOARD_NAME);
++ int ret = 0;
++ u32 i;
++
++ /* BIOS later than version 0.9.0 contains the right DMI data */
++ for (i = 0; board_name != NULL && bios_version != NULL &&
++ i < sizeof(bsp_data)/sizeof(struct platform_device); i++){
++
++ if (!strcmp(bsp_data[i].name, board_name)){
++
++ /* Register board */
++ platform_device_register(&bsp_data[i]);
++ found = true;
++
++ /* Galileo IDE expects this entry */
++ flash_version_data = simple_strtoul(bios_version, NULL, 16);
++ ret = add_firmware_sysfs_entry(bsp_data[i].name);
++
++ break;
++ }
++ }
++
++ /* For older BIOS without DMI data we read the data directly from flash */
++ if (found == false){
++ ret = intel_qrk_board_data_init_legacy();
++ }
++
++ return ret;
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Intel Quark SPI Data API");
++MODULE_LICENSE("Dual BSD/GPL");
++subsys_initcall(intel_qrk_board_data_init);
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_esram.c
+@@ -0,0 +1,1144 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark eSRAM overlay driver
++ *
++ * eSRAM is an on-chip fast access SRAM.
++ *
++ * This driver provides the ability to map a kallsyms derived symbol of
++ * arbitrary length or a struct page entitiy.
++ * A sysfs interface is provided to allow map of kernel structures, without
++ * having to use the API from your code directly.
++ *
++ * Example:
++ * echo idt_table > /sys/devices/intel-qrk-esram.0/map
++ *
++ * An API is provided to allow for mapping of a) kernel symbols or b) pages.
++ * eSRAM requires 4k physically aligned addresses to work - so a struct page
++ * fits neatly into this.
++ *
++ * intel_qrk_esram_map_sym(ohci_irq);
++ * intel_qrk_esram_map_page(virt_to_page(ohci_irq), "ohci_irq");
++ * Are equivalent - with the exception that map_sym() can detect if a mapping
++ * crosses a page-boundary, whereas map_page just maps one page. Generally use
++ * map_sym() for code and map_page() for data
++ *
++ * To populte eSRAM we must copy data to a temporary buffer, overlay and
++ * then copy data back to the eSRAM region.
++ *
++ * When entering S3 - we must save eSRAM state to DRAM, and similarly on restore
++ * to S0 we must repopulate eSRAM
++ * Unmap code is included for reference however the cache coherency of unmap is
++ * not guaranteed so the functionality is not exported by this code
++ *
++ */
++#include <asm/cacheflush.h>
++#include <asm/desc.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/special_insns.h>
++#include <asm-generic/uaccess.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/kallsyms.h>
++#include <linux/list.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/seq_file.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/timer.h>
++
++#include "intel_qrk_esram.h"
++
++#define DRIVER_NAME "intel-qrk-esram"
++
++/* Shorten fn names to fit 80 char limit */
++#ifndef sb_read
++#define sb_read intel_qrk_sb_read_reg
++#endif
++#ifndef sb_write
++#define sb_write intel_qrk_sb_write_reg
++#endif
++
++/* Define size of pages, ECC scrub demark etc */
++#define MAX_PAGE_RETRIES (100)
++#define MS_PER_HOUR (3600000UL)
++#define ESRAM_PAGE_COUNT INTEL_QRK_ESRAM_PAGE_COUNT
++#define ESRAM_PAGE_MASK (0xFFFFF000)
++#define ESRAM_PAGE_SIZE INTEL_QRK_ESRAM_PAGE_SIZE
++#define ESRAM_TOTAL_SIZE (ESRAM_PAGE_COUNT * ESRAM_PAGE_SIZE)
++#define ECC_MAX_REFRESH_PERIOD (48)
++#define ECC_DEFAULT_REFRESH_PERIOD (24)
++#define ECC_DRAM_READSIZE (512) /* bytes per DRAM ECC */
++#define ECC_ESRAM_READSIZE ESRAM_PAGE_SIZE /* bytes per SRAM ECC */
++
++/* Register ID */
++#define ESRAM_PGPOOL_REG (0x80) /* PGPOOL */
++#define ESRAM_CTRL_REG (0x81) /* ESRAMCTRL */
++#define ESRAM_PGBLOCK_REG (0x82) /* Global page ctrl */
++#define ESCRM_ECCCERR_REG (0x83) /* Correctable ECC */
++#define ESRAM_ECCUCERR_REG (0x84) /* Uncorrectable ECC */
++
++/* Reg commands */
++#define ESRAM_CTRL_READ (0x10) /* Config reg */
++#define ESRAM_CTRL_WRITE (0x11) /* Config reg */
++#define ESRAM_PAGE_READ (0x12) /* Page config read */
++#define ESRAM_PAGE_WRITE (0x13) /* Page config write */
++
++/* ESRAMPGPOOL reg 0x80 - r/w opcodes 0x10/0x11 */
++#define ESRAM_PGPOOL_FLUSHING(x) ((x>>18)&0x1FF)
++#define ESRAM_PGPOOL_PGBUSY(x) ((x>>9)&0x1FF)
++
++/* ESRAMCTRL reg 0x81 - r/w opcodes 0x10/0x11 */
++#define ESRAM_CTRL_FLUSHPRI(x) ((x>>25)&0x03) /* DRAM flush priority */
++#define ESRAM_CTRL_SIZE(x) ((x>>16)&0xFF) /* # of 4k pages */
++#define ESRAM_CTRL_ECCTHRESH(x) ((x>>8)&0xFF) /* ECC threshold */
++#define ESRAM_CTRL_THRESHMSG_EN (0x00000080) /* ECC notification */
++#define ESRAM_CTRL_ISAVAIL (0x00000010) /* ESRAM on die ? */
++#define ESRAM_CTRL_BLOCK_MODE (0x00000008) /* Block mode enable */
++#define ESRAM_CTRL_GLOBAL_LOCK (0x00000004) /* Global lock status */
++#define ESRAM_CTRL_FLUSHDISABLE (0x00000002) /* Global flush/dis */
++#define ESRAM_CTRL_SECDEC (0x00000001) /* ECC enable bit */
++
++/* PGBLOCK reg 0x82 - opcode 0x10/0x11 */
++#define ESRAM_PGBLOCK_FLUSHEN (0x80000000) /* Block flush enable */
++#define ESRAM_PGBLOCK_PGFLUSH (0x40000000) /* Flush the block */
++#define ESRAM_PGBLOCK_DISABLE (0x20000000) /* Block mode disable */
++#define ESRAM_PGBLOCK_ENABLE (0x10000000) /* Block mode enable */
++#define ESRAM_PGBLOCK_LOCK (0x08000000) /* Block mode lock en */
++#define ESRAM_PGBLOCK_INIT (0x04000000) /* Block init in prog */
++#define ESRAM_PGBLOCK_BUSY (0x01000000) /* Block is enabled */
++#define ESRAM_PGBLOCK_SYSADDR(x) (x&0x000000FF)
++
++/* ESRAMPGCTRL - opcode 0x12/0x13 */
++#define ESRAM_PAGE_FLUSH_PAGE_EN (0x80000000) /* S3 autoflush */
++#define ESRAM_PAGE_FLUSH (0x40000000) /* Flush page to DRAM */
++#define ESRAM_PAGE_DISABLE (0x20000000) /* page disable bit */
++#define ESRAM_PAGE_EN (0x10000000) /* Page enable */
++#define ESRAM_PAGE_LOCK (0x08000000) /* Page lock en */
++#define ESRAM_PAGE_INITIALISING (0x04000000) /* Init in progress */
++#define ESRAM_PAGE_BUSY (0x01000000) /* Page busy */
++#define ESRAM_PAGE_MAP_SHIFT (12) /* Shift away 12 LSBs */
++
++/* Extra */
++#define ESRAM_MAP_OP (0x01)
++#define ESRAM_UNMAP_OP (0x00)
++
++/**
++ * struct esram_refname
++ *
++ * Structure to hold a linked list of names
++ */
++struct esram_refname {
++ char name[KSYM_SYMBOL_LEN]; /* Name of mapping */
++ struct list_head list;
++};
++
++/**
++ * struct esram_page
++ *
++ * Represents an eSRAM page in our linked list
++ */
++struct esram_page {
++
++ struct list_head list; /* List entry descriptor */
++ struct list_head name_list; /* Linked list for name references */
++ u32 id; /* Page ID */
++ u32 phys_addr; /* Physial address of page */
++ u32 refcount; /* Reference count */
++ u32 vaddr; /* Virtual address of page */
++
++};
++
++/**
++ * struct intel_qrk_esram_dev
++ *
++ * Structre to represent module state/data/etc
++ */
++struct intel_qrk_esram_dev{
++
++ /* Linux kernel structures */
++ struct list_head page_used; /* Used pages */
++ struct list_head page_free; /* Free pages */
++ spinlock_t slock; /* Spinlock */
++ struct platform_device *pldev; /* Platform device */
++
++ /* Actual data */
++ struct esram_page * pages;
++ u8 cbuf[ESRAM_PAGE_SIZE];
++
++ /* Stats */
++ u32 page_count; /* As reported by silicon */
++ u32 page_disable_retries; /* Aggreate count on disable */
++ u32 page_enable_retries; /* Aggregate spin count page enable */
++ u32 page_free_ct; /* Free pages for mapping code section */
++};
++
++static struct intel_qrk_esram_dev esram_dev;
++
++/*
++ * Kallsyms does not provide data addresses. To map important structures such as
++ * the idt and gdt, we need to frig the lookup with the below. Other entities
++ * can similarly be added. Note we map a page from the given address - anything
++ * larger will require additional code to handle
++ */
++struct esram_symex {
++ char * name;
++ void * vaddr;
++ u32 size;
++};
++
++static struct esram_symex esram_symex[] =
++{
++ {
++ .name = "idt_table",
++ .vaddr = &idt_table,
++ .size = ESRAM_PAGE_SIZE,
++ },
++ {
++ .name = "gdt_page",
++ .vaddr = &gdt_page,
++ .size = ESRAM_PAGE_SIZE,
++ },
++};
++
++/**
++ * intel_qrk_esram_stat_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates eSRAM state via /sys/device/intel-qrk-esram.0/stat
++ */
++static ssize_t intel_qrk_esram_stat_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++
++{
++ struct esram_page * epage = NULL;
++ int len = 0;
++ unsigned int count = PAGE_SIZE, size;
++ u32 pgpool = 0, ctrl = 0, pgblock = 0;
++ char * enabled = "enabled";
++ char * disabled = "disabled";
++
++ /* Display page-pool relevant data */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGPOOL_REG, &pgpool, 1);
++ size = snprintf(buf, count,
++ "esram-pgpool\t\t\t: 0x%08x\n"
++ "esram-pgpool.free\t\t: %u\n"
++ "esram-pgpool.flushing\t\t: %u\n",
++ pgpool, ESRAM_PGPOOL_PGBUSY(pgpool)+1,
++ ESRAM_PGPOOL_FLUSHING(pgpool) + 1);
++ len += size;
++ count -= size;
++
++ /* Display ctrl reg - most of this is of interest */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
++ size = snprintf(buf + len, count - len,
++ "esram-ctrl\t\t\t: 0x%08x\n"
++ "esram-ctrl.ecc\t\t\t: %s\n"
++ "esram-ctrl.ecc-theshold\t\t: %u\n"
++ "esram-ctrl.pages\t\t: %u\n"
++ "esram-ctrl.dram-flush-priorityi\t: %u\n",
++ ctrl, (ctrl & ESRAM_CTRL_SECDEC) ? enabled : disabled,
++ ESRAM_CTRL_ECCTHRESH(ctrl), ESRAM_CTRL_SIZE(ctrl)+1,
++ ESRAM_CTRL_FLUSHPRI(ctrl));
++ len += size;
++ count -= size;
++
++ /* Display block ctrl/stat - we should be !block mode */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &pgblock, 1);
++ size = snprintf(buf + len, count - len, "esram-block\t\t\t: 0x%08x\n",
++ pgblock);
++ len += size;
++ count -= size;
++
++ /* Print ECC status regs */
++
++ /* Print per-page info */
++ size = snprintf(buf + len, count - len,
++ "free page\t\t\t: %u\nused page\t\t\t: %u\n"
++ "refresh \t\t\t: %ums\npage enable retries\t\t: %u\n"
++ "page disable retries\t: %u\n",
++ esram_dev.page_free_ct,
++ esram_dev.page_count-esram_dev.page_free_ct,
++ 0,
++ esram_dev.page_enable_retries,
++ esram_dev.page_disable_retries);
++ len += size;
++ count -= size;
++
++ spin_lock(&esram_dev.slock);
++ if(!list_empty(&esram_dev.page_free)){
++
++ epage = list_first_entry(&esram_dev.page_free, struct esram_page, list);
++ size = snprintf(buf + len, count - len,
++ "ecc next page \t\t\t: %u\n",epage->id);
++ len += size;
++ count -= size;
++
++
++ }
++ spin_unlock(&esram_dev.slock);
++
++ /* Return len indicate eof */
++ return len;
++}
++
++/**
++ * intel_qrk_esram_map_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Read back eSRAM mapped entries
++ */
++static ssize_t
++intel_qrk_esram_map_show(struct device *dev,struct device_attribute *attr,
++ char *buf)
++{
++ struct esram_page * epage = NULL;
++ struct esram_refname * refname = NULL;
++ int len = 0, size = 0;
++ unsigned int count = PAGE_SIZE;
++
++ spin_lock(&esram_dev.slock);
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ /* Print references */
++ list_for_each_entry(refname, &epage->name_list, list){
++ size = snprintf(buf + len, count - len,
++ "%s ", refname->name);
++ len += size;
++ count -= size;
++ }
++ /* Print data */
++ size += snprintf(buf + len, count - len,
++ "\n\tPage virt 0x%08x phys 0x%08x\n"
++ "\tRefcount %u\n",
++ epage->vaddr, epage->phys_addr,
++ epage->refcount);
++ len += size;
++ count -= size;
++ }
++ spin_unlock(&esram_dev.slock);
++
++ /* Return len indicate eof */
++ return len;
++}
++
++/**
++ * intel_qrk_esram_map_store
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: input buffer
++ * @param size: size of input data
++ * @return number of bytes successfully written
++ *
++ * Function allows user-space to switch mappings on/off with a simple
++ * echo idt_table > /sys/devices/intel-qrk-esram.0/map type command
++ */
++static ssize_t
++intel_qrk_esram_map_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ ssize_t ret = 0;
++ char * sbuf = NULL;
++ unsigned long vaddr = 0, i = 0;
++ unsigned int count = PAGE_SIZE;
++
++ if(count <= 1){
++ return -EINVAL;
++ }
++
++ /* Get input */
++ sbuf = (char*)buf;
++
++ /* Fixup entity to scrub spaces */
++ while(sbuf < (buf + count)){
++ if(*sbuf == ' ' || *sbuf == '\r' || *sbuf =='\n'){
++ *sbuf = 0;
++ break;
++ }
++ sbuf++;
++ }
++
++ /* Check to see if we are being asked to map a non-kallsyms addr */
++ for(i = 0; i < sizeof(esram_symex)/sizeof(struct esram_symex); i++){
++ if(strcmp(buf, esram_symex[i].name) == 0){
++ ret = intel_qrk_esram_map_range(
++ esram_symex[i].vaddr,
++ esram_symex[i].size,
++ esram_symex[i].name);
++ goto done;
++ }
++ }
++
++ /* This path relies on kallsyms to provide name/address data */
++ vaddr = kallsyms_lookup_name(buf);
++ if(vaddr == 0)
++ goto done;
++
++ ret = intel_qrk_esram_map_symbol((void*)vaddr);
++done:
++ if(ret == 0)
++ ret = (ssize_t)count;
++ return ret;
++}
++
++static struct device_attribute dev_attr_stats = {
++ .attr = {
++ .name = "stats",
++ .mode = 0444,
++ },
++ .show = intel_qrk_esram_stat_show,
++};
++
++static struct device_attribute dev_attr_map = {
++ .attr = {
++ .name = "map",
++ .mode = 0644,
++ },
++ .show = intel_qrk_esram_map_show,
++ .store = intel_qrk_esram_map_store,
++};
++
++static struct attribute *platform_attributes[] = {
++ &dev_attr_stats.attr,
++ &dev_attr_map.attr,
++ NULL,
++};
++
++static struct attribute_group esram_attrib_group = {
++ .attrs = platform_attributes
++};
++
++/******************************************************************************
++ * eSRAM Core
++ ******************************************************************************/
++
++/**
++ * intel_qrk_esram_page_busy
++ *
++ * @param epage: Pointer to the page descriptor
++ * @return boolean indicating whether or not a page is enabled
++ */
++static int intel_qrk_esram_page_busy(struct esram_page * epage, u8 lock)
++{
++ u32 reg = 0;
++
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, epage->id, &reg, lock);
++ return (reg&(ESRAM_PAGE_BUSY | ESRAM_PAGE_FLUSH | ESRAM_PAGE_DISABLE));
++}
++
++/**
++ * intel_qrk_esram_fault
++ *
++ * Dump eSRAM registers and kernel panic
++ * Nothing else to do at this point
++ */
++void intel_qrk_esram_fault(struct esram_page * epage, u32 lineno)
++{
++ u32 reg = 0, next = 0, prev = 0, prev_reg = 0;
++ u32 next_reg = 0, block = 0, ctrl = 0;
++
++ pr_err("eSRAM: fault @ %s:%d\n", __FILE__, lineno);
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, epage->id, &reg, 1);
++ pr_err("read page %d state 0x%08x\n", epage->id, reg);
++ if(epage->id == 0){
++ next = 1; prev = 127;
++ }else if(epage->id == 127){
++ next = 0; prev = 126;
++ }else{
++ next = epage->id+1;
++ prev = epage->id-1;
++ }
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, next, &next_reg, 1);
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, prev, &prev_reg, 1);
++
++ /* Get state */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &block, 1);
++
++ pr_err("eSRAM: CTRL 0x%08x block 0x%08x\n", ctrl, block);
++ pr_err("Prev page %d state 0x%08x Next page %d state 0x%08x\n"
++ , next, next_reg, prev, prev_reg);
++ BUG();
++}
++
++
++/**
++ * intel_qrk_esram_page_enable
++ *
++ * @param epage: struct esram_page carries data to program to register
++ * @param lock: Indicates whether to attain sb spinlock or not
++ *
++ * Enable an eSRAM page spinning for page to become ready.
++ */
++static void intel_qrk_esram_page_enable(struct esram_page *epage, u8 lock)
++{
++ u32 ret = 0;
++
++ /* Fault if we try to enable a disabled page */
++ if(intel_qrk_esram_page_busy(epage, lock)){
++ intel_qrk_esram_fault(epage, __LINE__);
++ }
++
++ /* Program page mapping */
++ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
++ ESRAM_PAGE_FLUSH_PAGE_EN | ESRAM_PAGE_EN |
++ (epage->phys_addr>>ESRAM_PAGE_MAP_SHIFT), lock);
++ do {
++ /* Poll until page busy bit becomes true */
++ ret = intel_qrk_esram_page_busy(epage, lock);
++
++ /* This branch should rarely if ever be true */
++ if(unlikely(ret == 0)){
++ esram_dev.page_enable_retries++;
++ }
++
++ }while(ret == 0);
++}
++
++/**
++ * intel_qrk_esram_page_disable_sync
++ *
++ * @param epage: pointer to eSRAM page descriptor
++ *
++ * This function spins waiting for disable bit to clear, useful right after a
++ * disable/disable-flush command. Interrupts are enabled here, sleeping is OK
++ */
++static void intel_qrk_esram_page_disable_sync(struct esram_page * epage)
++{
++ u32 ret = 0, retries = 0;
++ do {
++ /* Poll for busy bit clear */
++ ret = intel_qrk_esram_page_busy(epage, 1);
++
++ /* This branch should rarely if ever be true */
++ if(unlikely(ret)){
++ esram_dev.page_disable_retries++;
++ retries++;
++ }
++
++ if(retries == MAX_PAGE_RETRIES){
++ intel_qrk_esram_fault(epage, __LINE__);
++ }
++ }while(ret);
++}
++
++/**
++ * intel_qrk_esram_page_disable
++ *
++ * @param epage: struct esram_page carries data to program to register
++ *
++ * Disable the eSRAM page no flush. Interrupts are enabled here, sleeping is OK
++ */
++static void intel_qrk_esram_page_disable(struct esram_page *epage)
++{
++ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
++ ESRAM_PAGE_DISABLE, 1);
++ intel_qrk_esram_page_disable_sync(epage);
++}
++
++/**
++ * intel_qrk_esram_page_flush_disable
++ *
++ * @param epage: struct esram_page carries data to program to register
++ *
++ * Disable the eSRAM page - with flush. Note the architecture will block access
++ * to the overlayed region until the flush has completed => irqs may be switched
++ * on during this operation.
++ */
++static void intel_qrk_esram_page_flush_disable(struct esram_page *epage)
++{
++
++
++ /* Do flush */
++ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
++ ESRAM_PAGE_FLUSH | ESRAM_PAGE_DISABLE, 1);
++
++ intel_qrk_esram_page_disable_sync(epage);
++}
++
++#if 0
++/**
++ * intel_qrk_esram_flush_disable_all
++ *
++ * Flushes and disables all enabled eSRAM pages
++ */
++static void intel_qrk_esram_page_flush_disable_all(void)
++{
++ struct esram_page * epage = NULL;
++
++ spin_lock(&esram_dev.slock);
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ intel_qrk_esram_page_flush_disable(epage);
++ }
++ spin_unlock(&esram_dev.slock);
++}
++#endif
++
++/**
++ * intel_qrk_esram_page_populate_atomic
++ *
++ * @param epage: Pointer to eSRAM page desciptor.
++ * @return 0 placeholder, later versions may return error
++ *
++ * Function takes the mappings given in epage and uses the values to populate
++ * an eSRAM page. The copy/enable/copy routine must be done atomically, since we
++ * may be doing a memcpy() of an ISR for example.
++ * For this reason we wrapper this entire call into a callback provided by
++ * side-band, which does a spin_lock_irqsave calls this function and then does
++ * a spin_lock_irqrestore - thus guaranteeing atomicity of the below code and
++ * respect for the locking strategy of the side-band driver
++ */
++static int intel_qrk_esram_page_populate_atomic(struct esram_page * epage)
++{
++ unsigned long crz;
++
++ /* Copy away */
++ memcpy(&esram_dev.cbuf, (void*)epage->vaddr, ESRAM_PAGE_SIZE);
++
++ /* If CR0.WP is true - flip it HSD # 4930660 */
++ crz = read_cr0();
++ if (crz & X86_CR0_WP){
++ write_cr0(crz & (~X86_CR0_WP));
++ }
++
++ /* Disable NMI */
++ outb(0x80, 0x70);
++
++ /* Enable page mapping */
++ intel_qrk_esram_page_enable(epage, 0);
++
++ /* Copy back - populating memory overlay */
++ memcpy((void*)epage->vaddr, &esram_dev.cbuf, ESRAM_PAGE_SIZE);
++
++ /* Re-enable NMI */
++ outb(0x00, 0x70);
++
++ /* Restore CR0.WP if appropriate HSD # 4930660 */
++ if (crz & X86_CR0_WP){
++ write_cr0(crz);
++ }
++ return 0;
++}
++
++/**
++ * intel_qrk_esram_page_populate
++ *
++ * @param epage: Pointer to eSRAM page desciptor.
++ * @return 0 on success < 0 on failure
++ *
++ * Populates the page. set_memory_rw/set_memory_ro require local irqs enabled.
++ * intel_qrk_esram_page_populate_atomic - needs irqs switched off since memory
++ * can be inconsistent during the populate operation. Depopulate operations are
++ * architecturally guaranteed
++ */
++static int intel_qrk_esram_page_populate(struct esram_page * epage)
++{
++ int flip_rw = 0, level = 0, ret = 0;
++ pte_t * pte = epage != NULL ? lookup_address(epage->vaddr, &level):NULL;
++
++ if(unlikely(pte == NULL)){
++ return -EINVAL;
++ }
++
++ /* Determine if we need to set writable */
++ flip_rw = !(pte_write(*pte));
++
++ /* Ensure memory is r/w - do so before spin_lock_irqsave */
++ if(flip_rw){
++ ret = set_memory_rw(epage->vaddr, 1);
++ if (ret != 0){
++ pr_err("%s error during set_memory_rw = %d\n",
++ __func__, ret);
++ return ret;
++ }
++ }
++
++ /* Force ECC update @ disable only */
++ intel_qrk_esram_page_enable(epage, 1);
++ intel_qrk_esram_page_disable(epage);
++
++ /* Enable and populate eSRAM page using callback in sb with irqs off */
++ ret |= intel_qrk_sb_runfn_lock(
++ (int (*)(void*))intel_qrk_esram_page_populate_atomic,(void*)epage);
++
++ /* If we set memory writable - restore previous state */
++ if(flip_rw){
++ ret |= set_memory_ro(epage->vaddr, 1);
++ if (ret != 0){
++ pr_err("%s error during set_memory_ro = %d\n",
++ __func__, ret);
++ return ret;
++ }
++ }
++
++ return ret;
++}
++/**
++ * intel_qrk_esram_page_addref
++ *
++ * @param epage: eSRAM page descriptor
++ * @param name: Name of reference to add
++ * @return zero on success negative on error
++ *
++ */
++static int intel_qrk_esram_page_addref(struct esram_page * epage, char * name)
++{
++ struct esram_refname * refname = NULL;
++ if(unlikely(epage == NULL || name == NULL)){
++ return -EINVAL;
++ }
++
++ refname = kzalloc(sizeof(struct esram_refname), GFP_KERNEL);
++ if(unlikely(refname == NULL)){
++ return -ENOMEM;
++ }
++
++ /* Add to list */
++ strncpy(refname->name, name, sizeof(refname->name));
++ list_add(&refname->list, &epage->name_list);
++
++ /* Bump reference count */
++ epage->refcount++;
++ return 0;
++}
++
++
++/**
++ * __intel_qrk_esram_map_page
++ *
++ * @param page: Page to map
++ * @param name: Name of the mapping
++ * @return 0 success < 0 failure
++ *
++ * Overlay a vritual address rangne eeds to be aligned to a 4k address.
++ * Since multiple items can live in a 4k range, it is possible when calling
++ * into map_page() that a previous mapping will have already covered some or all
++ * of the mapping we want. This is not an error case, if the map function finds
++ * it is being asked to map a 4k range already mapped it returns 0, to indicate
++ * the mapping has suceeded i.e. it's already been mapped. This is logical if
++ * you think about it. In contrast being asked to unmap a region not mapped is
++ * clearly an error...
++ *
++ */
++static int __intel_qrk_esram_map_page(u32 vaddr, char * name)
++{
++ int ret = 0;
++ struct esram_page * epage = NULL;
++ struct esram_refname * refname = NULL;
++
++ if(unlikely(name == NULL)){
++ return -EINVAL;
++ }
++
++ if(unlikely(esram_dev.page_free_ct == 0)){
++ return -ENOMEM;
++ }
++
++ /* Verify if we have already mapped */
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ if(epage->vaddr == vaddr){
++
++ /* Page already mapped */
++ list_for_each_entry(refname, &epage->name_list, list){
++ if(strcmp(refname->name, name)==0){
++ /* Page mapped at this name */
++ return -EINVAL;
++ }
++ }
++ /* New symbol in previous mapping */
++ return intel_qrk_esram_page_addref(epage, name);
++ }
++ }
++
++ /* Enumerate eSRAM page structure */
++ epage = list_first_entry(&esram_dev.page_free, struct esram_page, list);
++ epage->phys_addr = virt_to_phys((void*)vaddr);
++ epage->vaddr = vaddr;
++ ret = intel_qrk_esram_page_addref(epage, name);
++ if(unlikely(ret < 0)){
++ return ret;
++ }
++
++ /* Populate page */
++ ret = intel_qrk_esram_page_populate(epage);
++
++ /* Move to used list */
++ list_move(&epage->list, &esram_dev.page_used);
++ esram_dev.page_free_ct--;
++
++ return ret;
++}
++
++/**
++ * __intel_qrk_esram_unmap_page
++ *
++ * @param page: Page to unmap
++ * @param name: Name of the mapping
++ * @return 0 success < 0 failure
++ *
++ * Unmap a previously mapped virutal address range.
++ * Must be 4k aligned
++ *
++ */
++static int __intel_qrk_esram_unmap_page(u32 vaddr, char * name)
++{
++ u8 found = 0;
++ struct esram_page * epage = NULL;
++ struct esram_refname * refname = NULL;
++
++ /* Find physical address */
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ if(epage->vaddr == vaddr){
++ found = 1;
++ break;
++ }
++ }
++
++ /* Bail out on error */
++ if(found == 0){
++ pr_err("0x%08x not mapped\n", vaddr);
++ return -EINVAL;
++ }
++
++ /* Determine reference to delete */
++ found = 0;
++ list_for_each_entry(refname, &epage->name_list, list){
++ if(strcmp(refname->name,name)==0){
++ found = 1;
++ break;
++ }
++ }
++ if(unlikely(found == 0)){
++ pr_err("No mapping %s!\n", name);
++ return -EINVAL;
++ }
++
++ /* Remove entry decrement reference count */
++ list_del(&refname->list);
++ kfree(refname);
++ if(--epage->refcount > 0){
++ return 0;
++ }
++
++ /* Flush and disable page */
++ intel_qrk_esram_page_flush_disable(epage);
++
++ /* Move to free list tail - scrub entries come from head */
++ list_move_tail(&epage->list, &esram_dev.page_free);
++ esram_dev.page_free_ct++;
++
++ return 0;
++}
++
++/**
++ *
++ * __intel_qrk_esram_page_op
++ *
++ * @param vaddr: Virtual address of symbol
++ * @param size: Size/length of symbol
++ * @param name: Name of mapping
++ * @param map: Boolean indicates whether to map or unmap the page
++ * @return 0 success < 0 failure
++ *
++ * This function maps/unmaps a pages/pages given at the given vaddr. If
++ * the extent of the symbol @ vaddr crosses a page boundary, then we map
++ * multiple pages. Other stuff inside the page, gets a performance boost 'for
++ * free'. Any other data in the page that crosses the physical page boundary
++ * will be partially mapped.
++ */
++static int __intel_qrk_esram_page_op(u32 vaddr, u32 size, char *name, u8 map)
++{
++ unsigned long offset = 0, page_offset = 0;
++ u32 pages = size/ESRAM_PAGE_SIZE + ((size%ESRAM_PAGE_SIZE) ? 1 : 0);
++ int ret = 0;
++
++ /* Compare required pages to available pages */
++ if(map == ESRAM_MAP_OP){
++ if(pages > esram_dev.page_free_ct)
++ return -ENOMEM;
++ }else{
++ if(pages > esram_dev.page_count - esram_dev.page_free_ct)
++ return -ENOMEM;
++ }
++
++ /* Align to 4k and iterate the mappings */
++ vaddr = vaddr&ESRAM_PAGE_MASK;
++ while(size > 0){
++
++ /* Map the page */
++ spin_lock(&esram_dev.slock);
++ if(map == ESRAM_MAP_OP){
++ ret = __intel_qrk_esram_map_page(vaddr, name);
++
++ }else{
++ ret = __intel_qrk_esram_unmap_page(vaddr, name);
++ }
++ spin_unlock(&esram_dev.slock);
++ if(unlikely(ret != 0)){
++ break;
++ }
++
++ /* Calc appropriate offsets */
++ page_offset = offset_in_page(vaddr);
++ if(page_offset + size > ESRAM_PAGE_SIZE){
++
++ offset = ESRAM_PAGE_SIZE - page_offset;
++ size -= offset;
++ vaddr += ESRAM_PAGE_SIZE;
++
++ }else{
++ size = 0;
++ }
++ }
++
++ return ret;
++}
++
++/******************************************************************************
++ * eSRAM API
++ ******************************************************************************/
++
++/**
++ * intel_qrk_esram_map_range
++ *
++ * @param vaddr: Virtual address to start mapping (must be 4k aligned)
++ * @param size: Size to map from
++ * @param mapname: Mapping name
++ * @return 0 success < 0 failure
++ *
++ * Map 4k increments at given address to eSRAM.
++ */
++int intel_qrk_esram_map_range(void * vaddr, u32 size, char * mapname)
++{
++ if(size == 0 || mapname == NULL || vaddr == NULL){
++ return -EINVAL;
++ }
++ return __intel_qrk_esram_page_op((u32)vaddr, size, mapname, ESRAM_MAP_OP);
++}
++EXPORT_SYMBOL(intel_qrk_esram_map_range);
++
++/**
++ * intel_qrk_esram_map_symbol
++ *
++ * @param vaddr: Virtual address of the symbol
++ * @return 0 success < 0 failure
++ *
++ * Maps a series of 4k chunks starting at vaddr&0xFFFFF000. vaddr shall be a
++ * kernel text section symbol (kernel or loaded module)
++ *
++ * We get the size of the symbol from kallsyms. We guarantee to map the entire
++ * size of the symbol - plus whatever padding is necessary to get alignment to
++ * eSRAM_PAGE_SIZE
++ * Other stuff inside the mapped pages will get a performance boost 'for free'.
++ * If this free boost is not what you want then
++ *
++ * 1. Align to 4k
++ * 2. Pad to 4k
++ * 3. Call intel_qrk_esram_map_range()
++ */
++int intel_qrk_esram_map_symbol(void * vaddr)
++{
++ long unsigned int size = 0, offset = 0;
++ char symname[KSYM_SYMBOL_LEN];
++
++ kallsyms_lookup_size_offset((long unsigned int)vaddr, &size, &offset);
++ if(size == 0){
++ return -EINVAL;
++ }
++ sprint_symbol(symname, (u32)vaddr);
++
++ return __intel_qrk_esram_page_op((u32)vaddr, size, symname, 1);
++}
++EXPORT_SYMBOL(intel_qrk_esram_map_symbol);
++
++/******************************************************************************
++ * Module/PowerManagement hooks
++ ******************************************************************************/
++
++/**
++ * intel_qrk_esram_suspend
++ *
++ * @param pdev: Platform device structure (unused)
++ * @param pm: Power managment descriptor
++ * @return 0 success < 0 failure
++ *
++ * For each enabled page - flush to DRAM and disable eSRAM page.
++ * For each 4k region the architecture guarantees atomicity of flush/disable.
++ * Hence any memory transactions to the affected region will stall until
++ * flush/disable completes - hence interrupts are left on.
++ */
++static int intel_qrk_esram_suspend(struct device * pdev)
++{
++ /* Flush and disable of eSRAM pages is carried out automatically */
++ return 0;
++}
++
++/**
++ * intel_qrk_esram_resume
++ *
++ * @param pm: Power management descriptor
++ * @return 0 success < 0 failure
++ *
++ * Runs after resume_noirq. Switches pages back to ro, if appropriate. We do
++ * this here since interrupts will be on, as required by the function
++ * set_memory_ro. If it were possible to set memory ro in resume_noirq we would
++ * do it there instead
++ */
++static int intel_qrk_esram_resume(struct device * pdev)
++{
++ struct esram_page * epage = NULL;
++ int ret = 0;
++
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ ret |= intel_qrk_esram_page_populate(epage);
++ }
++
++ return ret;
++}
++
++
++/**
++ * intel_qrk_esram_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This driver manages eSRAM on a per-page basis. Therefore if we find block
++ * mode is enabled, or any global, block-level or page-level locks are in place
++ * at module initialisation time - we bail out.
++ */
++static int intel_qrk_esram_probe(struct platform_device * pdev)
++{
++ int ret = 0;
++ u32 block = 0, ctrl = 0, i = 0, pgstat = 0;
++
++ memset(&esram_dev, 0x00, sizeof(esram_dev));
++ INIT_LIST_HEAD(&esram_dev.page_used);
++ INIT_LIST_HEAD(&esram_dev.page_free);
++ spin_lock_init(&esram_dev.slock);
++ esram_dev.page_free_ct = 0;
++
++ /* Ensure block mode disabled */
++ block = ESRAM_PGBLOCK_DISABLE;
++ sb_write(SB_ID_ESRAM, ESRAM_CTRL_WRITE, ESRAM_PGBLOCK_REG, block, 1);
++
++ /* Get state */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &block, 1);
++
++ /* Verify state is good to go */
++ if (ctrl & ESRAM_CTRL_GLOBAL_LOCK){
++ pr_err ("eSRAM: global lock @ 0x%08x\n", ctrl);
++ return -ENODEV;
++ }
++
++ if (block & (ESRAM_PGBLOCK_LOCK | ESRAM_PGBLOCK_ENABLE)){
++ pr_err ("eSRAM: lock @ 0x%08x\n", block);
++ return -ENODEV;
++ }
++ pr_info("eSRAM: CTRL 0x%08x block 0x%08x\n", ctrl, block);
++
++ /* Calculate # of pages silicon supports */
++ esram_dev.page_count = ESRAM_CTRL_SIZE(ctrl) + 1;
++ esram_dev.page_free_ct = esram_dev.page_count;
++ pr_info("eSRAM: pages %d\n", esram_dev.page_free_ct);
++
++ if(esram_dev.page_free_ct <= 1){
++ pr_err("Too few pages reported by eSRAM sub-system\n");
++ return -ENOMEM;
++ }
++
++ /* Allocate an appropriate number of pages */
++ esram_dev.pages = kzalloc(esram_dev.page_count *
++ sizeof(struct esram_page), GFP_KERNEL);
++ if (esram_dev.pages == NULL){
++ return -ENOMEM;
++ }
++
++ /* Initialise list of free pages, explicitely disable as we go */
++ for(i = 0; i < esram_dev.page_count; i++){
++ INIT_LIST_HEAD(&esram_dev.pages[i].name_list);
++ esram_dev.pages[i].id = i;
++
++ /* Read & verify page state */
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, i, &pgstat, 1);
++ if(pgstat & (ESRAM_PAGE_BUSY | ESRAM_PAGE_LOCK)){
++ pr_err("eSRAM: page %d state 0x%08x err\n", i, pgstat);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ list_add(&esram_dev.pages[i].list, &esram_dev.page_free);
++ }
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &esram_attrib_group);
++ if (ret)
++ goto err;
++
++ return 0;
++err:
++ kfree(esram_dev.pages);
++ return ret;
++}
++
++/*
++ * Power management operations
++ */
++static const struct dev_pm_ops intel_qrk_esram_pm_ops = {
++ .suspend = intel_qrk_esram_suspend,
++ .resume = intel_qrk_esram_resume,
++};
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_qrk_esram_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &intel_qrk_esram_pm_ops,
++ },
++ .probe = intel_qrk_esram_probe,
++};
++
++module_platform_driver(intel_qrk_esram_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Quark eSRAM overlay/ECC-scrub driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_esram.h
+@@ -0,0 +1,107 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark eSRAM overlay driver
++ *
++ * eSRAM is an on-chip fast access SRAM.
++ *
++ * This driver provides the ability to map a kallsyms derived symbol of
++ * arbitrary length or a struct page entitiy.
++ * A proc interface is provided to allow map/unmap of kernel structures, without
++ * having to use the API from your code directly.
++ *
++ * Example:
++ * echo ehci_irq on > /proc/driver/esram/map
++ * echo ehci_irq off > /proc/driver/esram/map
++ *
++ * An API is provided to allow for mapping of a) kernel symbols or b) pages.
++ * eSRAM requires 4k physically aligned addresses to work - so a struct page
++ * fits neatly into this.
++ *
++ * To populte eSRAM we must copy data to a temporary buffer, overlay and
++ * then copy data back to the eSRAM region.
++ *
++ * When entering S3 - we must save eSRAM state to DRAM, and similarly on restore
++ * to S0 we must repopulate eSRAM
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
++ */
++#ifndef __INTEL_QRK_ESRAM_H__
++#define __INTEL_QRK_ESRAM_H__
++
++#include <linux/module.h>
++
++/* Basic size of an eSRAM page */
++#define INTEL_QRK_ESRAM_PAGE_SIZE (0x1000)
++#define INTEL_QRK_ESRAM_PAGE_COUNT (0x80)
++/**
++ * intel_qrk_esram_map_range
++ *
++ * @param vaddr: Virtual address to start mapping (must be 4k aligned)
++ * @param size: Size to map from
++ * @param mapname: Mapping name
++ * @return 0 success < 0 failure
++ *
++ * Map 4k increments at given address to eSRAM.
++ */
++int intel_qrk_esram_map_range(void * vaddr, u32 size, char * mapname);
++
++/**
++ * intel_qrk_esram_unmap_range
++ *
++ * @param vaddr: The virtual address to unmap
++ * @return 0 success < 0 failure
++ *
++ * Logical corollary of esram_map_page
++ */
++int intel_qrk_esram_unmap_range(void * vaddr, u32 size, char * mapname);
++
++/**
++ * intel_qrk_esram_map_symbol
++ *
++ * @param vaddr: Virtual address of the symbol
++ * @return 0 success < 0 failure
++ *
++ * Maps a series of 4k chunks starting at vaddr&0xFFFFF000. vaddr shall be a
++ * kernel text section symbol (kernel or loaded module)
++ *
++ * We get the size of the symbol from kallsyms. We guarantee to map the entire
++ * size of the symbol - plus whatever padding is necessary to get alignment to
++ * eSRAM_PAGE_SIZE
++ * Other stuff inside the mapped pages will get a performance boost 'for free'.
++ * If this free boost is not what you want then
++ * 1. Align to 4k
++ * 2. Pad to 4k
++ * 3. Call intel_qrk_esram_map_range()
++ */
++int intel_qrk_esram_map_symbol(void * vaddr);
++
++/**
++ * intel_qrk_esram_unmap_symbol
++ *
++ * @param vaddr: Virtual address of the symbol
++ * @return 0 success < 0 failure
++ *
++ * Logical corollary to intel_qrk_esram_map_symbol
++ * Undoes any mapping of pages starting at sym for sym's size
++ */
++int intel_qrk_esram_unmap_symbol(void * vaddr);
++
++#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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_esram_test.c
+@@ -0,0 +1,602 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/**
++ * intel_qrk_esram_test.c
++ *
++ * Simple test module to provide test cases for ITS integration
++ *
++ */
++#include <linux/cdev.h>
++#include <linux/crc32.h>
++#include <linux/crc32c.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/kallsyms.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++
++#include "intel_qrk_esram.h"
++#include "intel_qrk_esram_test.h"
++
++#define DRIVER_NAME "intel_qrk_esram_test"
++
++/**
++ * struct intel_qrk_esram_dev
++ *
++ * Structre to represent module state/data/etc
++ */
++struct intel_qrk_esram_test_dev{
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++ char * pdata;
++ u32 size;
++};
++
++static struct intel_qrk_esram_test_dev esram_test_dev;
++static struct class *esram_test_class;
++static DEFINE_MUTEX(esram_test_mutex);
++static int esram_test_major;
++static char * name = "testmap";
++
++/******************************************************************************
++ * eSRAM BIST
++ ******************************************************************************/
++
++static int crc_cache = 0;
++
++unsigned long long tsc_delta(unsigned long long first, unsigned long long end)
++{
++ if (first < end)
++ return end - first;
++ else
++ return (ULLONG_MAX - first) + end;
++}
++
++
++/**
++ * intel_qrk_crctest
++ *
++ * Do a CRC32 of the specified region. Return the time taken in jiffies
++ */
++static unsigned long long intel_qrk_crctest(char * pdata, u32 crcsize)
++{
++ unsigned long long j1 = 0, j2 = 0;
++
++ rdtscll(j1);
++
++ /* Flush LMT cache to introduce cache miss to our test */
++ __asm__ __volatile__("wbinvd\n");
++ crc32(0, pdata, crcsize);
++
++ rdtscll(j2);
++
++ return tsc_delta(j1, j2);
++}
++
++#ifdef __DEBUG__
++#define bist_err(x){\
++ pr_err("eSRAM bist err line %d errno %d\n", (__LINE__-2), x);\
++ return x;\
++}
++#else
++#define bist_err(x){\
++ return x;\
++}
++#endif
++/**
++ * intel_qrk_esram_perpage_overlay
++ *
++ * Maps to integration test spec ID CLN.F.SW.APP.eSRAM.0
++ */
++int intel_qrk_esram_test_perpage_overlay(void)
++{
++
++ int ret = 0;
++ u32 idx = 0, size = INTEL_QRK_ESRAM_PAGE_SIZE;
++
++ /* Set a known state */
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ *((u32*)&esram_test_dev.pdata[idx]) = idx;
++ }
++
++
++ /* Basic test of full range of memory */
++ ret = intel_qrk_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ if(*((u32*)&esram_test_dev.pdata[idx]) != idx){
++ pr_err("Entry %d is 0x%08x require 0x%08x",
++ idx, esram_test_dev.pdata[idx], idx);
++ bist_err(-EIO);
++ }
++ }
++
++#if 0
++ ret = intel_qrk_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_qrk_esram_test_pageref_count
++ *
++ * Ensure page reference couting works as expected
++ */
++int intel_qrk_esram_test_pagref_count(void)
++{
++ u32 size = INTEL_QRK_ESRAM_PAGE_SIZE;
++ int ret = 0;
++
++ return 0;
++ /* Map a page */
++ ret = intel_qrk_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Map a second time - and verify mapping fails */
++ ret = intel_qrk_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret == 0){
++ bist_err(-EFAULT);
++ }
++
++#if 0
++ /* Unmap - OK */
++ ret = intel_qrk_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Verify second unmap operation fails */
++ ret = intel_qrk_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret == 0){
++ bist_err(-EFAULT);
++ }
++#endif
++ return 0;
++}
++
++extern uint32_t get_crc32table_le(void);
++
++/**
++ * intel_qrk_esram_test_contig_perfmetric
++ *
++ * Do a CRC16 for a contigous area of memory
++ * Map contigous area and get a CRC16
++ *
++ * Ensure overlayed data takes less time than regular unoverlayed DRAM
++ */
++int intel_qrk_esram_test_contig_perfmetric(void)
++{
++ u32 crcsize = 0x60000;
++ unsigned long long crc32_fullmap = 0, crc32_fullunmap = 0;
++ uint32_t crc32table_le = kallsyms_lookup_name("crc32table_le");
++ int ret = 0;
++
++ if (crc32table_le == 0){
++ pr_err("%s unable to fine symbol crc32table_le\n", __func__);
++ return -ENODEV;
++ }
++
++ /* Get raw data metric */
++ crc_cache = 1;
++ crc32_fullunmap = intel_qrk_crctest(esram_test_dev.pdata, crcsize);
++
++ /* Map CRC16 symbol (algorithm) + code (data) */
++ ret = intel_qrk_esram_map_symbol(crc32_le);
++ if(ret){
++ bist_err(ret);
++ }
++ ret = intel_qrk_esram_map_symbol((void*)crc32table_le);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Map test data */
++ ret = intel_qrk_esram_map_range(esram_test_dev.pdata, crcsize, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Get metric */
++ crc_cache = 1;
++ crc32_fullmap = intel_qrk_crctest(esram_test_dev.pdata, crcsize);
++#if 0
++ /* Tidy up */
++ ret = intel_qrk_esram_unmap_range(esram_test_dev.pdata, crcsize, name);
++ if(ret){
++ bist_err(ret);
++ }
++ ret = intel_qrk_esram_unmap_range(((void*)crc32_table),
++ sizeof(crc32_table), name);
++ if(ret){
++ bist_err(ret);
++ }
++ ret = intel_qrk_esram_unmap_symbol(crc32);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ pr_info("%s did crctest - mapped - in %llu ticks\n", __func__, crc32_fullmap);
++ pr_info("%s mapped count %llu unmapped %llu\n",
++ __func__, crc32_fullmap, crc32_fullunmap);
++ return crc32_fullmap < crc32_fullunmap;
++}
++
++/**
++ * intel_qrk_esram_test_kernel_codemap
++ *
++ * Maps some kernel code - a data section and then calls the code contained
++ * therein. Proves out the running overlayed eSRAM works
++ */
++int intel_qrk_esram_test_kernel_codemap(void)
++{
++#if 0
++ int ret = intel_qrk_esram_map_symbol(msleep);
++ if(ret){
++ printk(KERN_ERR "%s map symbol msleep fail\n", __FUNCTION__);
++ bist_err(ret);
++ }
++
++ /* run the mapped code */
++ msleep(1);
++
++ /* unmap */
++ ret = intel_qrk_esram_unmap_symbol(msleep);
++ if(ret){
++ printk(KERN_ERR "%s unmap symbol msleep fail\n", __FUNCTION__);
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_qrk_esram_test_kernel_datamap
++ *
++ * Tests mapping/unmapping of a kernel data structure
++ */
++int intel_qrk_esram_test_kernel_datamap(void)
++{
++#if 0
++ unsigned long jtag = 0;
++ unsigned long ctrl = 0;
++
++ /* Map the interrupt descriptor table */
++ int ret = intel_qrk_esram_map_range(idt_table, INTEL_QRK_ESRAM_PAGE_SIZE, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ jtag = jiffies;
++ /* Wait for jiffies to tick or timeout to occur (failure) */
++ while(jtag == jiffies){
++ ctrl++;
++ }
++
++ /* unmap */
++ ret = intel_qrk_esram_unmap_range(idt_table, INTEL_QRK_ESRAM_PAGE_SIZE, name);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_qrk_esram_test_sub_unsub
++ *
++ * Subscribe and unsubscribe 100% of available eSRAM
++ */
++int intel_qrk_esram_test_sub_unsub(void)
++{
++ int ret = 0;
++ u32 idx = 0, size = INTEL_QRK_ESRAM_PAGE_SIZE * INTEL_QRK_ESRAM_PAGE_COUNT;
++
++ /* Set a known state */
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ *((u32*)&esram_test_dev.pdata[idx]) = idx;
++ }
++
++ /* Basic test of full range of memory */
++ ret = intel_qrk_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ if(*((u32*)&esram_test_dev.pdata[idx]) != idx){
++ pr_err("Entry %d is 0x%08x require 0x%08x",
++ idx, esram_test_dev.pdata[idx], idx);
++ bist_err(-EIO);
++ }
++ }
++#if 0
++ ret = intel_qrk_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_qrk_esram_test_over_sub
++ *
++ * Test oversubscription of eSRAM
++ */
++int intel_qrk_esram_test_over_sub(void)
++{
++ int ret = 0;
++ u32 size = INTEL_QRK_ESRAM_PAGE_SIZE * (INTEL_QRK_ESRAM_PAGE_COUNT + 1);
++
++ /* Over subscribe should fail */
++ ret = intel_qrk_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret == 0){
++ //intel_qrk_esram_unmap_range(esram_test_dev.pdata, size, name);
++ bist_err(-EFAULT);
++ }
++ return 0;
++}
++
++/*
++ * File ops
++ */
++static long esram_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -EINVAL;
++
++ cmd -= QRK_ESRAM_IOCTL_BASE;
++ switch (cmd) {
++ case QRK_F_SW_APP_ESRAM_0:
++ /* Per page overlay */
++ ret = intel_qrk_esram_test_perpage_overlay();
++ break;
++
++ case QRK_F_SW_APP_ESRAM_1:
++ /* Verify page reference counting */
++ ret = intel_qrk_esram_test_pagref_count();
++ break;
++
++ case QRK_F_SW_APP_ESRAM_2:
++ /* Performance metric or overlay contig RAM */
++ ret = intel_qrk_esram_test_contig_perfmetric();
++ if (ret == 1)
++ ret = 0;
++ break;
++
++ case QRK_F_SW_APP_ESRAM_3:
++ /* Verify mapping of kernel code section */
++ /* Covered by test #2 */
++ ret = 0; //intel_qrk_esram_test_kernel_codemap();
++ break;
++
++ case QRK_F_SW_APP_ESRAM_4:
++ /* Verify mapping of kernel data section (IDT) */
++ /* Covered by test #2 */
++ ret = 0; //intel_qrk_esram_test_kernel_datamap();
++ break;
++
++ case QRK_F_SW_APP_ESRAM_5:
++ /* Complete subscribe/unsubscribe eSRAM */
++ ret = intel_qrk_esram_test_sub_unsub();
++ break;
++
++ case QRK_F_SW_APP_ESRAM_6:
++ /* Over subscribe eSRAM */
++ ret = intel_qrk_esram_test_over_sub();
++ break;
++
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int esram_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&esram_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&esram_test_dev.open_lock)) {
++ mutex_unlock(&esram_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (esram_test_dev.opened) {
++ mutex_unlock(&esram_test_dev.open_lock);
++ mutex_unlock(&esram_test_mutex);
++ return -EINVAL;
++ }
++
++ esram_test_dev.opened++;
++ mutex_unlock(&esram_test_dev.open_lock);
++ mutex_unlock(&esram_test_mutex);
++
++ return 0;
++}
++
++static int esram_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&esram_test_dev.open_lock);
++ esram_test_dev.opened = 0;
++ mutex_unlock(&esram_test_dev.open_lock);
++
++ return 0;
++}
++
++static const struct file_operations esram_test_file_ops = {
++ .open = esram_test_open,
++ .release = esram_test_release,
++ .unlocked_ioctl = esram_test_ioctl,
++ .llseek = no_llseek,
++};
++
++
++/**
++ * intel_qrk_esram_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This driver manages eSRAM on a per-page basis. Therefore if we find block
++ * mode is enabled, or any global, block-level or page-level locks are in place
++ * at module initialisation time - we bail out.
++ */
++static int intel_qrk_esram_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ esram_test_dev.size = INTEL_QRK_ESRAM_PAGE_COUNT * INTEL_QRK_ESRAM_PAGE_SIZE;
++
++ /* Get memory */
++ esram_test_dev.pdata = kzalloc(esram_test_dev.size, GFP_KERNEL);
++ if(unlikely(esram_test_dev.pdata == NULL)){
++ pr_err("Can't allocate %d bytes\n", esram_test_dev.size);
++ return -ENOMEM;
++ }
++
++ mutex_init(&esram_test_dev.open_lock);
++ cdev_init(&esram_test_dev.cdev, &esram_test_file_ops);
++ esram_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&esram_test_dev.cdev, MKDEV(esram_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ kfree(esram_test_dev.pdata);
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(esram_test_class, NULL,
++ MKDEV(esram_test_major, minor), NULL,
++ "esramtest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ kfree(esram_test_dev.pdata);
++ return -EINVAL;
++ }
++ printk(KERN_INFO "%s/%s/%s complete OK !!\n", __FUNCTION__, __DATE__,__TIME__);
++ return 0;
++
++}
++
++/**
++ * intel_qrk_esram_remove
++ *
++ * @return 0 success < 0 failure
++ *
++ * Removes a platform device
++ */
++static int intel_qrk_esram_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(esram_test_dev.cdev.dev);
++
++ device_destroy(esram_test_class, MKDEV(esram_test_major, minor));
++ cdev_del(&esram_test_dev.cdev);
++ kfree(esram_test_dev.pdata);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_qrk_esram_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_qrk_esram_test_remove,
++};
++
++/**
++ * intel_qrk_esram_init
++ *
++ * @return 0 success < 0 failure
++ *
++ * Module entry point
++ */
++static int __init intel_qrk_esram_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ esram_test_class = class_create(THIS_MODULE,"qrk_esram_test");
++ if (IS_ERR(esram_test_class)) {
++ retval = PTR_ERR(esram_test_class);
++ printk(KERN_ERR "esram_test: can't register earam_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "esram_test");
++ if (retval) {
++ printk(KERN_ERR "earam_test: can't register character device\n");
++ goto err_class;
++ }
++ esram_test_major = MAJOR(dev);
++
++ memset(&esram_test_dev, 0x00, sizeof(esram_test_dev));
++ esram_test_dev.pldev = platform_create_bundle(
++ &intel_qrk_esram_test_driver, intel_qrk_esram_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(esram_test_dev.pldev)){
++ printk(KERN_ERR "platform_create_bundle fail!\n");
++ retval = PTR_ERR(esram_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(esram_test_class);
++err:
++ return retval;
++}
++
++/**
++ * intel_qrk_esram_exit
++ *
++ * Module exit
++ */
++static void __exit intel_qrk_esram_test_exit(void)
++{
++ platform_device_unregister(esram_test_dev.pldev);
++ platform_driver_unregister(&intel_qrk_esram_test_driver);
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Quark eSRAM ITS driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++module_init(intel_qrk_esram_test_init);
++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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_esram_test.h
+@@ -0,0 +1,43 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/**
++ * intel_qrk_esram_test.h
++ *
++ * Define integers for ioctl operation
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
++ */
++
++#ifndef __INTEL_QRK_ESRAM_TEST_H__
++#define __INTEL_QRK_ESRAM_TEST_H__
++
++#define QRK_ESRAM_IOCTL_BASE 255
++#define QRK_F_SW_APP_ESRAM_0 0x00000000
++#define QRK_F_SW_APP_ESRAM_1 0x00000001
++#define QRK_F_SW_APP_ESRAM_2 0x00000002
++#define QRK_F_SW_APP_ESRAM_3 0x00000003
++#define QRK_F_SW_APP_ESRAM_4 0x00000004
++#define QRK_F_SW_APP_ESRAM_5 0x00000005
++#define QRK_F_SW_APP_ESRAM_6 0x00000006
++#define QRK_F_SW_APP_ESRAM_7 0x00000007
++#define QRK_F_SW_APP_ESRAM_8 0x00000008
++
++#endif /* __INTEL_QRK_ESRAM_TEST_H__ */
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_imr.c
+@@ -0,0 +1,697 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark IMR driver
++ *
++ * IMR stand for Insolate Memory Region, supported by Quark SoC.
++ *
++ * A total number of 8 IMRs have implemented by Quark SoC,
++ * Some IMRs might be already occupied by BIOS or Linux during
++ * booting time.
++ *
++ * A user can cat /sys/devices/platform/intel-qrk-imr/status for current IMR
++ * status
++ *
++ * To allocate an IMR addresses must be alinged to 1k
++ *
++ * The IMR alloc API will locate the next available IMR slot set up
++ * with input memory region, then apply the input access right masks
++ *
++ * The IMR can be freed with the pre-allocated memory addresses.
++ */
++
++#include <asm-generic/uaccess.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/proc_fs.h>
++
++#include "intel_qrk_imr.h"
++#include <asm/imr.h>
++
++#define DRIVER_NAME "intel-qrk-imr"
++
++#define IMR_READ_MASK 0x1
++#define IMR_MAX_ID 7
++
++#ifndef phys_to_virt
++#define phys_to_virt __va
++#endif
++
++/* IMR HW register address structre */
++struct qrk_imr_reg_t {
++ u8 imr_xl; /* high address register */
++ u8 imr_xh; /* low address register */
++ u8 imr_rm; /* read mask register */
++ u8 imr_wm; /* write mask register */
++} qrk_imr_reg_t;
++
++/**
++ * struct qrk_imr_addr_t
++ *
++ * IMR memory address structure
++ */
++struct qrk_imr_addr_t {
++ u32 addr_low; /* low boundary memroy address */
++ u32 addr_high; /* high boundary memory address */
++ u32 read_mask; /* read access right mask */
++ u32 write_mask; /* write access right mask */
++} qrk_imr_addr_t;
++
++/**
++ * struct qrk_imr_pack
++ *
++ * local IMR pack structure
++ */
++struct qrk_imr_pack {
++ bool occupied; /* IMR occupied */
++ bool locked; /* IMR lock */
++ struct qrk_imr_reg_t reg; /* predefined imr register address */
++ struct qrk_imr_addr_t addr; /* IMR address region structure */
++ unsigned char info[MAX_INFO_SIZE]; /* IMR info */
++} qrk_imr_pack;
++
++
++/* Predefined HW register address */
++static struct qrk_imr_reg_t imr_reg_value[] = {
++ { IMR0L, IMR0H, IMR0RM, IMR0WM },
++ { IMR1L, IMR1H, IMR1RM, IMR1WM },
++ { IMR2L, IMR2H, IMR2RM, IMR2WM },
++ { IMR3L, IMR3H, IMR3RM, IMR3WM },
++ { IMR4L, IMR4H, IMR4RM, IMR4WM },
++ { IMR5L, IMR5H, IMR5RM, IMR5WM },
++ { IMR6L, IMR6H, IMR6RM, IMR6WM },
++ { IMR7L, IMR7H, IMR7RM, IMR7WM }
++};
++
++static struct platform_device *pdev;
++
++/**
++ * module parameter
++ * IMR slot should repersant the available IMR region from
++ * linux boot and BIOS.
++ *
++ * For example: imr_bit_mask = 0x10111001
++ * occupied IMR: 0, 3, 4, 5, 7
++ * un-occupied IMR: 1, 2, 6
++ */
++static int imr_bit_mask = 0xFF;
++module_param(imr_bit_mask, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(imr_bit_mask, "IMR bit mask");
++
++/**
++ * module parameter
++ * if IMR lock is a nozero value, all unlocked
++ * imrs will be locked regardless the usage.
++ */
++static int imr_lock = 0;
++module_param(imr_lock, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(imr_lock, "switch to lock unused IMR");
++
++/* local IMR data structure */
++struct qrk_imr_pack local_imr[IMR_MAXID];
++
++static unsigned short host_id;
++
++/**
++ * intel_qrk_imr_read_reg
++ *
++ * @param reg: register address
++ * @return nothing
++ *
++ * return register value from input address.
++ */
++static inline uint32_t intel_qrk_imr_read_reg(uint8_t reg)
++{
++ uint32_t temp = 0;
++
++ intel_qrk_sb_read_reg(SB_ID_ESRAM, CFG_READ_OPCODE, reg, &temp, 0);
++ return temp;
++}
++
++/**
++ * intel_clm_imr_latch_data
++ *
++ * @return nothing
++ *
++ * Populate IMR data structure from HW.
++ */
++static inline void intel_clm_imr_latch_data(void)
++{
++ int i = 0;
++
++ for (i = 0; i < IMR_MAXID; i++) {
++
++ local_imr[i].addr.addr_low =
++ intel_qrk_imr_read_reg(imr_reg_value[i].imr_xl);
++ local_imr[i].addr.addr_high =
++ intel_qrk_imr_read_reg(imr_reg_value[i].imr_xh);
++ local_imr[i].addr.read_mask =
++ intel_qrk_imr_read_reg(imr_reg_value[i].imr_rm);
++ local_imr[i].addr.write_mask =
++ intel_qrk_imr_read_reg(imr_reg_value[i].imr_wm);
++
++ if (local_imr[i].addr.addr_low & IMR_LOCK_BIT)
++ local_imr[i].locked = true;
++
++ if (local_imr[i].addr.read_mask > 0 &&
++ local_imr[i].addr.read_mask < IMR_READ_ENABLE_ALL){
++ local_imr[i].occupied = true;
++ } else {
++ local_imr[i].occupied = false;
++ memcpy(local_imr[i].info, "NOT USED", MAX_INFO_SIZE);
++ }
++ }
++}
++
++/**
++ * prepare_input_addr
++ *
++ * @param addr: input physical memory address
++ * @return formated memory address
++ *
++ * 1. verify input memory address alignment
++ * 2. apply IMR_REG_MASK to match the format required by HW
++ */
++static inline uint32_t prepare_input_addr(uint32_t addr)
++{
++ if (addr & (IMR_MEM_ALIGN - 1))
++ return 0;
++
++ addr = (addr >> 8) & IMR_REG_MASK;
++ return addr;
++}
++
++/**
++ * intel_qrk_imr_find_free_entry
++ *
++ * @return the next free imr slot
++ */
++static int intel_qrk_imr_find_free_entry(void)
++{
++ int i = 0;
++
++ intel_clm_imr_latch_data();
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ if ((!local_imr[i].occupied) && (!local_imr[i].locked))
++ return i;
++ }
++
++ pr_err("%s: No more free IMR available.\n", __func__);
++ return -ENOMEM;
++}
++
++
++/**
++ * sb_write_chk
++ *
++ * @param id: Sideband identifier
++ * @param cmd: Command to send to destination identifier
++ * @param reg: Target register w/r to qrk_sb_id
++ * @param data: Data to write to target register
++ * @return nothing
++ *
++ * Set SB register and read back to verify register has been updated.
++ */
++static void sb_write_chk(qrk_sb_id id, u8 cmd, u8 reg, u32 data)
++{
++ u32 data_verify = 0;
++
++ intel_qrk_sb_write_reg(id, cmd, reg, data, 0);
++ intel_qrk_sb_read_reg(id, cmd, reg, &data_verify, 0);
++ BUG_ON(data != data_verify);
++}
++
++/**
++ * imr_add_entry
++ *
++ * @param id: imr slot id
++ * @param hi: hi memory address
++ * @param lo: lo memory address
++ * @param read: read access mask
++ * @param write: write access mask
++ * @return nothing
++ *
++ */
++static inline void imr_add_entry(int id, uint32_t hi, uint32_t lo,
++ uint32_t read, uint32_t write, bool lock)
++{
++ u32 val = 0;
++
++ intel_qrk_sb_read_reg(SB_ID_ESRAM, CFG_READ_OPCODE,
++ imr_reg_value[id].imr_xl, &val, 0);
++ val &= ~IMR_EN;
++ sb_write_chk(SB_ID_ESRAM, CFG_WRITE_OPCODE, imr_reg_value[id].imr_xl,
++ val);
++
++ sb_write_chk(SB_ID_ESRAM, CFG_WRITE_OPCODE, imr_reg_value[id].imr_rm,
++ read);
++ sb_write_chk(SB_ID_ESRAM, CFG_WRITE_OPCODE, imr_reg_value[id].imr_wm,
++ write);
++ sb_write_chk(SB_ID_ESRAM, CFG_WRITE_OPCODE, imr_reg_value[id].imr_xh,
++ hi);
++ sb_write_chk(SB_ID_ESRAM, CFG_WRITE_OPCODE, imr_reg_value[id].imr_xl,
++ lo);
++}
++
++/**
++ * x1000_imr_add_entry
++ *
++ * @param id: imr slot id
++ * @param hi: hi memory address
++ * @param lo: lo memory address
++ * @param read: read access mask
++ * @param write: write access mask
++ * @return nothing
++ *
++ */
++static inline void x1000_imr_add_entry(int id, uint32_t hi, uint32_t lo,
++ uint32_t read, uint32_t write, bool lock)
++{
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xl, lo, 0);
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xh, hi, 0);
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_rm, read, 0);
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_wm, write, 0);
++}
++
++/**
++ * intel_qrk_imr_add_entry
++ *
++ * @param id: imr slot id
++ * @param hi: hi memory address
++ * @param lo: lo memory address
++ * @param read: read access mask
++ * @param write: write access mask
++ * @return nothing
++ *
++ * Setup an IMR entry
++ */
++static void intel_qrk_imr_add_entry(int id, uint32_t hi,
++ uint32_t lo, uint32_t read, uint32_t write, bool lock)
++{
++ if (PCI_DEVICE_ID_X1000_HOST_BRIDGE == host_id)
++ x1000_imr_add_entry(id, hi, lo, read, write, lock);
++ else
++ imr_add_entry(id, hi, lo, read, write, lock);
++
++ if (lock) {
++ lo |= IMR_LOCK_BIT;
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xl, lo, 0);
++ }
++}
++
++/**
++ * get_phy_addr
++ * @return phy address value
++ *
++ * convert register format to physical address format.
++ */
++static uint32_t get_phy_addr(uint32_t reg_value)
++{
++ reg_value = ((reg_value & IMR_REG_MASK) << 8);
++ return reg_value;
++}
++
++
++
++/**
++ * intel_qrk_imr_init_mask
++ *
++ * @param mask: module parameter
++ * @return nothing
++ *
++ * prepare local IMR data structure from input module parameter.
++ */
++static void intel_qrk_imr_init_mask(int mask)
++{
++ int i = 0;
++
++ BUG_ON((mask > 255 || mask < 0));
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ local_imr[i].addr.addr_low =
++ intel_qrk_imr_read_reg(imr_reg_value[i].imr_xl);
++
++ /* mask bit 1 means imr occupied*/
++ if (((mask>>i) & IMR_READ_MASK) == 0) {
++ if (!(local_imr[i].addr.addr_low & IMR_LOCK_BIT))
++ intel_qrk_remove_imr_entry(i);
++ }
++ }
++}
++
++/**
++ * imr_rm_entry
++ *
++ * @param id: imr slot id
++ * @return nothing
++ *
++ */
++static inline void imr_rm_entry(int id)
++{
++ u32 val = 0;
++
++ intel_qrk_sb_read_reg(SB_ID_ESRAM, CFG_READ_OPCODE,
++ imr_reg_value[id].imr_xl, &val, 0);
++ val &= ~IMR_EN;
++ sb_write_chk(SB_ID_ESRAM, CFG_WRITE_OPCODE, imr_reg_value[id].imr_xl,
++ val);
++}
++
++/**
++ * x1000_imr_rm_entry
++ *
++ * @param id: imr slot id
++ * @return nothing
++ *
++ */
++static inline void x1000_imr_rm_entry(int id)
++{
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_rm, IMR_READ_ENABLE_ALL,
++ 0);
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_wm, IMR_WRITE_ENABLE_ALL,
++ 0);
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xl, IMR_BASE_ADDR, 0);
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xh, IMR_BASE_ADDR, 0);
++}
++
++/**
++ * intel_qrk_remove_imr_entry
++ *
++ * @param id: imr slot id
++ * @return nothing
++ *
++ * remove imr slot based on input id
++ */
++void intel_qrk_remove_imr_entry(int id)
++{
++ if (id >= IMR_MAXID || local_imr[id].locked)
++ return;
++
++ if (PCI_DEVICE_ID_X1000_HOST_BRIDGE == host_id)
++ x1000_imr_rm_entry(id);
++ else
++ imr_rm_entry(id);
++
++ intel_clm_imr_latch_data();
++
++}
++EXPORT_SYMBOL(intel_qrk_remove_imr_entry);
++
++/**
++ * intel_qrk_imr_alloc
++ *
++ * @param high: high boundary of memory address
++ * @param low: low boundary of memorry address
++ * @param read: IMR read mask value
++ * @param write: IMR write mask value
++ * @return nothing
++ *
++ * setup the next available IMR with customized read and write masks
++ */
++int intel_qrk_imr_alloc(uint32_t high, uint32_t low, uint32_t read,
++ uint32_t write, unsigned char *info, bool lock)
++{
++ int id = 0;
++
++ if (info == NULL)
++ return -EINVAL;
++
++ if ((low & IMR_LOCK_BIT) || (read == 0 || write == 0)) {
++ pr_err("%s: Invalid acces mode\n", __func__);
++ return -EINVAL;
++ }
++
++ /* Calculate aligned addresses and validate range */
++ high = prepare_input_addr(high);
++ low = prepare_input_addr(low);
++
++ /* Find a free entry */
++ id = intel_qrk_imr_find_free_entry();
++ if (id < 0)
++ return -ENOMEM;
++
++ /* Add entry - locking as necessary */
++ intel_qrk_imr_add_entry(id, high, low, (read & IMR_READ_ENABLE_ALL),
++ write, lock);
++
++ /* Name the new entry */
++ memcpy(local_imr[id].info, info, MAX_INFO_SIZE);
++
++ /* Update local data structures */
++ intel_clm_imr_latch_data();
++
++ pr_info("IMR alloc id %d 0x%08x - 0x%08x %s\n", id, low, high,
++ lock ? "locked" : "unlocked");
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_imr_alloc);
++
++/**
++ * intel_qrk_imr_free
++ *
++ * @param high: high boundary of memory address
++ * @param low: low boundary of memorry address
++ * @return nothing
++ *
++ * remove the imr based on input memory region
++ */
++int intel_qrk_imr_free(uint32_t high, uint32_t low)
++{
++ int i = 0;
++
++ if (low > high) {
++ pr_err("%s: Invalid input address values.\n", __func__);
++ return -EINVAL;
++ }
++
++ high = prepare_input_addr(high);
++ if (!high) {
++ pr_err("%s: Invalid input memory address.\n", __func__);
++ return -EINVAL;
++ }
++
++ low = prepare_input_addr(low);
++ if (!low) {
++ pr_err("%s: Invalid input memory address.\n", __func__);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ if (local_imr[i].occupied
++ && (local_imr[i].addr.addr_low == low)
++ && (local_imr[i].addr.addr_high == high)
++ && (!local_imr[i].locked)) {
++ intel_qrk_remove_imr_entry(i);
++ return 0;
++ }
++ }
++
++ return -EINVAL;
++}
++EXPORT_SYMBOL(intel_qrk_imr_free);
++
++/**
++ * intel_qrk_imr_init_data
++ *
++ * @return nothing
++ * initialize local_imr data structure
++ */
++static void intel_qrk_imr_init_data(void)
++{
++ int i = 0;
++ char * res_str = "System Reserved Region";
++ int len = strlen(res_str);
++
++ intel_clm_imr_latch_data();
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ local_imr[i].reg = imr_reg_value[i];
++ memcpy(local_imr[i].info, res_str, len);
++ }
++}
++
++/**
++ * intel_qrk_imr_lockall
++ *
++ * @param mask: module parameter
++ * @return nothing
++ *
++ * lock up all un-locked IMRs
++ */
++int intel_qrk_imr_lockall(void)
++{
++ int i = 0;
++ uint32_t temp_addr;
++
++ /* Enumerate IMR data structures */
++ intel_qrk_imr_init_data();
++ intel_qrk_imr_init_mask(imr_bit_mask);
++
++ /* Cycle through IMRs locking whichever are unlocked */
++ for (i = 0; i < IMR_MAXID; i++) {
++
++ temp_addr = local_imr[i].addr.addr_low;
++ if (!(temp_addr & IMR_LOCK_BIT)) {
++
++ DBG("%s: locking IMR %d\n", __func__, i);
++ temp_addr |= IMR_LOCK_BIT;
++ intel_qrk_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ local_imr[i].reg.imr_xl,
++ temp_addr, 0);
++ }
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_imr_lockall);
++
++/**
++ * intel_qrk_imr_stat_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates IMR state via /sys/device/intel-qrk-imr/stat
++ */
++static int intel_qrk_imr_stat_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ int len = 0;
++ int i = 0;
++ int size, count = PAGE_SIZE;
++ uint32_t hi_phy_addr, lo_phy_addr;
++
++ for (i = 0; i < IMR_MAXID; i++) {
++
++ /* read back the actual input physical memory address */
++ hi_phy_addr = get_phy_addr(local_imr[i].addr.addr_high);
++ lo_phy_addr = get_phy_addr(local_imr[i].addr.addr_low);
++
++ /* the IMR always protect extra 1k memory size above the input
++ * high reg value
++ */
++ size = ((hi_phy_addr - lo_phy_addr) / IMR_MEM_ALIGN) + 1;
++
++ size = snprintf(buf+len, count,
++ "imr - id : %d\n"
++ "info : %s\n"
++ "occupied : %s\n"
++ "locked : %s\n"
++ "size : %d kb\n"
++ "hi addr (phy): 0x%08x\n"
++ "lo addr (phy): 0x%08x\n"
++ "hi addr (vir): 0x%08x\n"
++ "lo addr (vir): 0x%08x\n"
++ "read mask : 0x%08x\n"
++ "write mask : 0x%08x\n\n",
++ i,
++ local_imr[i].info,
++ local_imr[i].occupied ? "yes" : "no",
++ local_imr[i].locked ? "yes" : "no",
++ size,
++ hi_phy_addr,
++ lo_phy_addr,
++ (uint32_t)phys_to_virt(hi_phy_addr),
++ (uint32_t)phys_to_virt(lo_phy_addr),
++ local_imr[i].addr.read_mask,
++ local_imr[i].addr.write_mask);
++ len += size;
++ count -= size;
++ }
++ return len;
++}
++
++static struct device_attribute dev_attr_stats = {
++ .attr = {
++ .name = "stat",
++ .mode = 0444, },
++ .show = intel_qrk_imr_stat_show,
++};
++
++static struct attribute *platform_attributes[] = {
++ &dev_attr_stats.attr,
++ NULL,
++};
++
++static struct attribute_group imr_attrib_group = {
++ .attrs = platform_attributes
++};
++
++/**
++ * intel_qrk_imr_init
++ *
++ * @param dev_id: Host Bridge's PCI device ID
++ * @return 0 success < 0 failue
++ *
++ * module entry point
++ */
++int intel_qrk_imr_init(unsigned short dev_id)
++{
++ int ret;
++
++ host_id = dev_id;
++
++ pdev = platform_device_alloc(DRIVER_NAME, -1);
++ if (!pdev)
++ return -ENOMEM;
++
++ ret = platform_device_add(pdev);
++ if (ret)
++ goto fail_platform;
++
++ /* initialise local imr data structure */
++ intel_qrk_imr_init_data();
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &imr_attrib_group);
++ if (ret)
++ goto fail_platform;
++
++ if(intel_qrk_imr_runt_setparams() == 0 && imr_lock == 1){
++ intel_qrk_imr_lockall();
++ }
++
++ return 0;
++
++fail_platform:
++ platform_device_del(pdev);
++ return ret;
++}
++EXPORT_SYMBOL(intel_qrk_imr_init);
++
++MODULE_DESCRIPTION("Intel Quark SOC IMR API ");
++MODULE_AUTHOR("Intel Corporation");
++MODULE_LICENSE("Dual BSD/GPL");
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_imr.h
+@@ -0,0 +1,157 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark IMR driver
++ *
++ * IMR stand for Insolate Memory Region, supported by Quark SoC.
++ *
++ * A total number of 8 IMRs have implemented by Quark SoC,
++ * some IMRs might be already occupied by BIOS or Linux booting time.
++ *
++ * Input addresses parameter required the actual Physical address.
++ *
++ * The IMR alloc API will locate the next available IMR slot set up
++ * with input memory region, and apply with the default access right
++ * (CPU & CPU_snoop enable).
++ *
++ * The alloc_mask API takes input read & write masks values to set up
++ * IMR with customized access right.
++ *
++ * User can free IMR with pre-alloc specified addresses.
++ */
++
++#ifndef __INTEL_QRK_IMR_H__
++#define __INTEL_QRK_IMR_H__
++
++#include <linux/intel_qrk_sb.h>
++#include "asm/io.h"
++
++#define CFG_READ_OPCODE 0x10 /* BUnit Control Read */
++#define CFG_WRITE_OPCODE 0x11 /* BUnit control write */
++
++/* DRAM IMR register addresses */
++#define IMR0L 0x40
++#define IMR0H 0x41
++#define IMR0RM 0x42
++#define IMR0WM 0x43
++#define IMR1L 0x44
++#define IMR1H 0x45
++#define IMR1RM 0x46
++#define IMR1WM 0x47
++#define IMR2L 0x48
++#define IMR2H 0x49
++#define IMR2RM 0x4A
++#define IMR2WM 0x4B
++#define IMR3L 0x4C
++#define IMR3H 0x4D
++#define IMR3RM 0x4E
++#define IMR3WM 0x4F
++#define IMR4L 0x50
++#define IMR4H 0x51
++#define IMR4RM 0x52
++#define IMR4WM 0x53
++#define IMR5L 0x54
++#define IMR5H 0x55
++#define IMR5RM 0x56
++#define IMR5WM 0x57
++#define IMR6L 0x58
++#define IMR6H 0x59
++#define IMR6RM 0x5A
++#define IMR6WM 0x5B
++#define IMR7L 0x5C
++#define IMR7H 0x5D
++#define IMR7RM 0x5E
++#define IMR7WM 0x5F
++
++#define IMR_EN 0x40000000
++#define IMR_LOCK_BIT 0x80000000
++#define IMR_WRITE_ENABLE_ALL 0xFFFFFFFF
++#define IMR_READ_ENABLE_ALL 0xBFFFFFFF
++#define IMR_REG_MASK 0xFFFFFC
++
++#define IMR_ESRAM_FLUSH_INIT 0x80000000 /* esram flush */
++#define IMR_SNOOP_ENABLE 0x40000000 /* core snoops */
++#define IMR_PUNIT_ENABLE 0x20000000
++#define IMR_SMM_ENABLE 0x02 /* core SMM access */
++#define IMR_NON_SMM_ENABLE 0x01 /* core non-SMM access */
++#define IMR_BASE_ADDR 0x00
++#define IMR_MEM_ALIGN 0x400
++
++#define MAX_INFO_SIZE 64
++#define IMR_MAXID 8
++
++/* snoop + Non SMM write mask */
++#define IMR_DEFAULT_MASK (IMR_SNOOP_ENABLE \
++ + IMR_ESRAM_FLUSH_INIT \
++ + IMR_NON_SMM_ENABLE)
++
++/* debug printk */
++#ifdef DEBUG
++#define DBG(args...) pr_info(args)
++#else
++#define DBG(args...)
++#endif
++
++extern unsigned long _text;
++extern unsigned long __init_begin;
++
++/**
++ * intel_qrk_imr_alloc
++ *
++ * @param high: the end of physical memory address
++ * @param low: the start of physical memory address
++ * @param read: IMR read mask value
++ * @param write: IMR write maks value
++ * @param info: imr information
++ * @param lock: imr lock
++ *
++ * Setup imr with customised read/ write masks
++ */
++int intel_qrk_imr_alloc(u32 high, u32 low, u32 read, u32 write,
++ unsigned char *info, bool lock);
++
++/**
++ * intel_qrk_imr_free
++ *
++ * @param high: high boundary of memory address
++ * @param low: low boundary of memorry address
++ *
++ * remove the imr based on input memory region
++ */
++int intel_qrk_imr_free(u32 high, u32 low);
++
++/**
++ * intel_qrk_remove_imr_entry
++ *
++ * @param id: internal imr data struct id
++ *
++ * Remove imr based on input imr data structure id
++ */
++void intel_qrk_remove_imr_entry(int id);
++
++/**
++ * intel_qrk_imr_init
++ *
++ * @param dev_id: Host Bridge's PCI device ID
++ * Initialise IMRs
++ */
++int intel_qrk_imr_init(unsigned short dev_id);
++
++#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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_imr_kernel.c
+@@ -0,0 +1,139 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark IMR driver
++ *
++ * IMR stand for Insolate Memory Region, supported by Quark SoC.
++ *
++ * The IMR id 3 is pre-defined as the use for kernel data protection
++ *
++ * The early imr protects entire memory (from the beginning of kernel text
++ * section to the top of memory) during linux boot time. In the linux run
++ * time, the protection need to resize down to memory region that only
++ * contains: kernel text, read only data, and initialized data section.
++ *
++ */
++#include <linux/errno.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/platform_data/quark.h>
++#include <linux/printk.h>
++#include "intel_qrk_imr.h"
++
++/* pre-defined imr id for uncompressed kernel */
++#define IMR_KERNEL_ID 3
++
++/**
++ * addr_hw_ready
++ *
++ * shift input address value to match HW required 1k aligned format
++ */
++static inline uint32_t addr_hw_ready(uint32_t addr)
++{
++ /* memory alignment */
++ addr &= (~((1 << 10) - 1));
++
++ /* prepare input addr in HW required format */
++ addr = (addr >> 8) & IMR_REG_MASK;
++ return addr;
++}
++
++/**
++ * void intel_qrk_imr_runt_kerndata_setup
++ *
++ * Setup imr for kernel text, read only data section
++ *
++ * The read only data (rodata) section placed between text and initialized data
++ * section by kernel.
++ */
++static void intel_qrk_imr_runt_kerndata_setup(void)
++{
++ uint32_t hi;
++ uint32_t lo;
++
++ hi = (uint32_t)virt_to_phys(&__init_begin);
++ lo = (uint32_t)virt_to_phys(&_text);
++
++ /* Set a locked IMR around the kernel .text section */
++ if (intel_qrk_imr_alloc((hi - IMR_MEM_ALIGN), lo,
++ IMR_DEFAULT_MASK, IMR_DEFAULT_MASK,
++ "KERNEL RUNTIME DATA", 1)) {
++ pr_err("IMR: Set up runtime kernel data imr faild!\n");
++ return;
++ }
++}
++
++/**
++ * intel_qrk_imr_teardown_unlocked
++ *
++ * Remove any unlocked IMR
++ *
++ */
++static void intel_qrk_imr_teardown_unlocked(void)
++{
++ int i = 0;
++ for (i = 0; i < IMR_MAXID; i++)
++ intel_qrk_remove_imr_entry(i);
++}
++
++/**
++ * intel_qrk_imr_runt_setparams
++ *
++ * set imr range for text, read only, initialised data in linux run time
++ */
++int intel_qrk_imr_runt_setparams(void)
++{
++ /* Setup an IMR around the kernel .text area */
++ intel_qrk_imr_runt_kerndata_setup();
++
++ /* Remove any other unlocked IMR */
++ intel_qrk_imr_teardown_unlocked();
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_imr_runt_setparams);
++
++/**
++ * intel_qrk_imr_runt_init
++ *
++ * module entry point
++ */
++static int __init intel_qrk_imr_runt_init(void)
++{
++ return 0;
++}
++
++/**
++ * intel_qrk_imr_runt_exit
++ *
++ * Module exit
++ */
++static void __exit intel_qrk_imr_runt_exit(void)
++{
++ /* do nothing */
++}
++
++MODULE_DESCRIPTION("Intel Quark SOC IMR API ");
++MODULE_AUTHOR("Intel Corporation");
++MODULE_LICENSE("Dual BSD/GPL");
++
++subsys_initcall(intel_qrk_imr_runt_init);
++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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_imr_test.c
+@@ -0,0 +1,357 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark IMR Test module
++ *
++ */
++
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++#include "intel_qrk_imr.h"
++
++#define DRIVER_NAME "intel_qrk_imr_test"
++
++/**
++ * XXX intel_qrk_sb.h needs to be updated with SB_ID_PUNIT and change
++ * propagated. This is a workaround to make it look less ugly. */
++#define SB_ID_PUNIT SB_ID_THERMAL
++
++/* Memory-mapped SPI Flash address */
++#define ILB_SPIFLASH_BASEADDR 0xFF800000
++/* PUnit DMA block transfer size, in bytes */
++#define SPI_DMA_BLOCK_SIZE 512
++
++/**************************** Exported to LISA *******************************/
++
++/*
++ * Internally-used ioctl code. At the moment it is not reserved by any mainline
++ * driver.
++ */
++#define IMR_TEST_IOCTL_CODE 0xE1
++
++/*
++ * Integers for ioctl operation.
++ */
++#define IOCTL_QRK_SANITY_CHECK_PUNIT_DMA _IO(IMR_TEST_IOCTL_CODE, 0x00)
++#define IOCTL_QRK_IMR_1 _IO(IMR_TEST_IOCTL_CODE, 0x01)
++
++/*****************************************************************************/
++
++/**
++ * struct intel_qrk_imr_dev
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_qrk_imr_test_dev {
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++};
++
++static struct intel_qrk_imr_test_dev imr_test_dev;
++static struct class *imr_test_class;
++static DEFINE_MUTEX(imr_test_mutex);
++static int imr_test_major;
++
++/* PUnit DMA registers over side-band */
++#define PUNIT_SPI_DMA_COUNT_REG 0x60
++#define PUNIT_SPI_DMA_DEST_REG 0x61
++#define PUNIT_SPI_DMA_SRC_REG 0x62
++
++/**
++ * ilb_spi_dma_read
++ *
++ * @param src: physical address in Legacy SPI Flash
++ * @param dst: physical address of destination
++ * @param dma_block_count: number of 512B SPI Flash blocks to be transferred
++ *
++ * Read-access iLB SPI via PUnit DMA engine.
++ *
++ */
++static void ilb_spi_dma_read(u32 *src, u32 *dst, u32 dma_block_count)
++{
++ pr_info("%s: src=%p, dst=%p, count=%u\n", __func__, src, dst,
++ dma_block_count);
++
++ /* Setup source and destination addresses. */
++ intel_qrk_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
++ PUNIT_SPI_DMA_SRC_REG, (u32) src, 0);
++ intel_qrk_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
++ PUNIT_SPI_DMA_DEST_REG, (u32) dst, 0);
++
++ pr_info("%s: starting transaction\n", __func__);
++
++ /*
++ * Setup the number of block to be copied over. Transaction will start
++ * as soon as the register is filled with value.
++ */
++ intel_qrk_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
++ PUNIT_SPI_DMA_COUNT_REG, dma_block_count, 0);
++
++ /* Poll for completion. */
++ while (dma_block_count > 0) {
++ intel_qrk_sb_read_reg(SB_ID_PUNIT, CFG_READ_OPCODE,
++ PUNIT_SPI_DMA_COUNT_REG, &dma_block_count, 0);
++ }
++
++ pr_info("%s: transaction completed\n", __func__);
++}
++
++/**
++ * punit_dma_sanity_check
++ *
++ * @return 0 if success, 1 if failure
++ *
++ * Perform a basic sanity check for PUnit DMA engine. Copy over a 512B SPI
++ * Flash block.
++ */
++static int punit_dma_sanity_check(void)
++{
++ int err = 0;
++ u32 *buffer = NULL;
++ u32 buf_ph_addr = 0;
++
++ /* Allocate 512B buffer for 1 SPI Flash block */
++ buffer = kzalloc(SPI_DMA_BLOCK_SIZE, GFP_KERNEL);
++ if (!buffer) {
++ err = -ENOMEM;
++ goto end;
++ }
++
++ /* DMA first SPI Flash block into buffer */
++ buf_ph_addr = (u32)virt_to_phys(buffer);
++ ilb_spi_dma_read((u32 *)ILB_SPIFLASH_BASEADDR, (u32 *)buf_ph_addr, 1);
++
++ kfree(buffer);
++end:
++ return err;
++}
++
++/**
++ * imr_violate_kernel_punit_dma
++ *
++ * @return always 0
++ *
++ * PUnit-DMA access to the Uncompressed Kernel IMR.
++ * This is based on set_imr_kernel_data() in intel_qrk_imr.c. Find the physical
++ * address of .text section and copy a 512B chunk of legacy SPI via PuUnit DMA.
++ *
++ */
++static int imr_violate_kernel_punit_dma(void)
++{
++ extern unsigned long _text;
++ u32 kernel_text = (u32)virt_to_phys(&_text);
++
++ /* We expect this to trigger an IMR violation reset */
++ ilb_spi_dma_read((u32 *)ILB_SPIFLASH_BASEADDR, (u32 *)kernel_text, 1);
++
++ /*
++ * If we're still alive, we have a serious bug:
++ * - we didn't appropriately target the IMR?
++ * - if we have, weren't we prevented from accessing?
++ * - if we weren't prevented, it's unlikely we're alive with a dirty
++ * text section
++ */
++ pr_err("%s: BUG: still running after DMAing into kernel text!?\n",
++ __func__);
++
++ return 0;
++}
++
++/*
++ * File ops
++ */
++static long imr_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -EINVAL;
++
++ switch (cmd) {
++ case IOCTL_QRK_SANITY_CHECK_PUNIT_DMA:
++ /* Check PUnit DMA actually works */
++ ret = punit_dma_sanity_check();
++ break;
++ case IOCTL_QRK_IMR_1:
++ /* Kernel IMR violation: PUnit DMA access */
++ ret = imr_violate_kernel_punit_dma();
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int imr_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&imr_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&imr_test_dev.open_lock)) {
++ mutex_unlock(&imr_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (imr_test_dev.opened) {
++ mutex_unlock(&imr_test_dev.open_lock);
++ mutex_unlock(&imr_test_mutex);
++ return -EINVAL;
++ }
++
++ imr_test_dev.opened++;
++ mutex_unlock(&imr_test_dev.open_lock);
++ mutex_unlock(&imr_test_mutex);
++ return 0;
++}
++
++static int imr_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&imr_test_dev.open_lock);
++ imr_test_dev.opened = 0;
++ mutex_unlock(&imr_test_dev.open_lock);
++
++ return 0;
++}
++
++static const struct file_operations imr_test_file_ops = {
++ .open = imr_test_open,
++ .release = imr_test_release,
++ .unlocked_ioctl = imr_test_ioctl,
++ .llseek = no_llseek,
++};
++
++/**
++ * intel_qrk_imr_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ */
++static int intel_qrk_imr_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ mutex_init(&imr_test_dev.open_lock);
++ cdev_init(&imr_test_dev.cdev, &imr_test_file_ops);
++ imr_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&imr_test_dev.cdev, MKDEV(imr_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(imr_test_class, NULL,
++ MKDEV(imr_test_major, minor), NULL,
++ "imrtest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ return -EINVAL;
++ }
++
++ return 0;
++
++}
++
++static int intel_qrk_imr_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(imr_test_dev.cdev.dev);
++
++ device_destroy(imr_test_class, MKDEV(imr_test_major, minor));
++ cdev_del(&imr_test_dev.cdev);
++
++ class_destroy(imr_test_class);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_qrk_imr_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_qrk_imr_test_remove,
++};
++
++/**
++ * intel_qrk_imr_test_init
++ *
++ * Load module.
++ */
++static int __init intel_qrk_imr_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ imr_test_class = class_create(THIS_MODULE,"qrk_imr_test");
++ if (IS_ERR(imr_test_class)) {
++ retval = PTR_ERR(imr_test_class);
++ printk(KERN_ERR "imr_test: can't register imr_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "imr_test");
++ if (retval) {
++ printk(KERN_ERR "earam_test: can't register character device\n");
++ goto err_class;
++ }
++ imr_test_major = MAJOR(dev);
++
++ memset(&imr_test_dev, 0x00, sizeof(imr_test_dev));
++ imr_test_dev.pldev = platform_create_bundle(
++ &intel_qrk_imr_test_driver, intel_qrk_imr_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(imr_test_dev.pldev)){
++ printk(KERN_ERR "platform_create_bundle fail!\n");
++ retval = PTR_ERR(imr_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(imr_test_class);
++err:
++ return retval;
++}
++
++static void __exit intel_qrk_imr_test_exit(void)
++{
++ platform_device_unregister(imr_test_dev.pldev);
++ platform_driver_unregister(&intel_qrk_imr_test_driver);
++}
++
++module_init(intel_qrk_imr_test_init);
++module_exit(intel_qrk_imr_test_exit);
++
++MODULE_AUTHOR("Josef Ahmad <josef.ahmad@intel.com>");
++MODULE_DESCRIPTION("Quark IMR test module");
++MODULE_LICENSE("Dual BSD/GPL");
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_plat_clanton_hill.c
+@@ -0,0 +1,226 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "ClantonHill"
++#define GPIO_RESTRICT_NAME "qrk-gpio-restrict-nc"
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++#define AD7298_MAX_EXT_VIN_EXT_BATT 30000
++#define AD7298_MAX_EXT_VIN_INT_BATT 9200
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN_EXT_BATT, AD7298_MAX_EXT_VIN_INT_BATT }
++};
++
++/******************************************************************************
++ * Intel Quark SPI Controller Data
++ ******************************************************************************/
++static struct pxa2xx_spi_chip qrk_ffrd_spi_0_cs_0 = {
++ .gpio_cs = 8,
++};
++
++static struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &qrk_ffrd_spi_0_cs_0,
++ },
++};
++
++/******************************************************************************
++ * ST Microelectronics LIS331DLH I2C Device Platform Data
++ ******************************************************************************/
++#include <linux/platform_data/lis331dlh_intel_qrk.h>
++
++/* GPIO interrupt pins connected to the LIS331DLH */
++#define ST_ACCEL_INT1_GPIO 15
++#define ST_ACCEL_INT2_GPIO 4
++
++static struct lis331dlh_intel_qrk_platform_data lis331dlh_i2c_platform_data = {
++ .irq1_pin = ST_ACCEL_INT1_GPIO,
++};
++
++static struct gpio reserved_gpios[] = {
++ {
++ ST_ACCEL_INT1_GPIO,
++ GPIOF_IN,
++ "st_accel_i2c-int1"
++ },
++ {
++ ST_ACCEL_INT2_GPIO,
++ GPIOF_IN,
++ "st_accel_i2c-int2"
++ },
++};
++
++/* I2C device addresses */
++#define MAX9867_ADDR 0x18
++#define LIS331DLH_ADDR 0x19
++
++static struct i2c_adapter *i2c_adap;
++static struct i2c_board_info probed_i2c_lis331dlh = {
++ .platform_data = &lis331dlh_i2c_platform_data,
++};
++static struct i2c_board_info probed_i2c_max9867;
++static const unsigned short max9867_i2c_addr[] =
++ { MAX9867_ADDR, I2C_CLIENT_END };
++static const unsigned short lis331dlh_i2c_addr[] =
++ { LIS331DLH_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_qrk_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Clanton Hill platform
++ */
++static int intel_qrk_spi_add_onboard_devs(void)
++{
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++/**
++ * intel_qrk_gpio_restrict_probe
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_qrk_gpio_restrict_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ static int gpio_done, spi_done;
++ struct i2c_client *max9867 = NULL, *lis331dlh = NULL;
++
++ if (gpio_done)
++ goto spi;
++ ret = gpio_request_array(reserved_gpios, ARRAY_SIZE(reserved_gpios));
++ if (ret)
++ goto end;
++ gpio_done = 1;
++
++spi:
++ if (spi_done)
++ goto i2c;
++ ret = intel_qrk_spi_add_onboard_devs();
++ if (ret)
++ goto end;
++ spi_done = 1;
++i2c:
++ i2c_adap = i2c_get_adapter(0);
++ if (NULL == i2c_adap) {
++ pr_info("%s: i2c adapter not ready yet. Deferring..\n",
++ __func__);
++ ret = -EPROBE_DEFER;
++ goto end;
++ }
++ strlcpy(probed_i2c_max9867.type, "intel-qrk-max9867", I2C_NAME_SIZE);
++ max9867 = i2c_new_probed_device(i2c_adap, &probed_i2c_max9867,
++ max9867_i2c_addr, i2c_probe);
++ strlcpy(probed_i2c_lis331dlh.type, "lis331dlh_qrk", I2C_NAME_SIZE);
++ lis331dlh = i2c_new_probed_device(i2c_adap, &probed_i2c_lis331dlh,
++ lis331dlh_i2c_addr, i2c_probe);
++ i2c_put_adapter(i2c_adap);
++
++ if (NULL == max9867 || NULL == lis331dlh) {
++ pr_err("%s: can't probe I2C devices\n", __func__);
++ ret = -ENODEV;
++ goto end;
++ }
++
++end:
++ 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_clanton_hill_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ ret = platform_driver_register(&gpio_restrict_pdriver);
++
++ return ret;
++}
++
++static int intel_qrk_plat_clanton_hill_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver qrk_clanton_hill_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_plat_clanton_hill_probe,
++ .remove = intel_qrk_plat_clanton_hill_remove,
++};
++
++module_platform_driver(qrk_clanton_hill_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Clanton Hill BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_plat_clanton_peak.c
+@@ -0,0 +1,227 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Clanton Peak board entry point
++ *
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/spi_gpio.h>
++
++#define DRIVER_NAME "ClantonPeakSVP"
++#define GPIO_RESTRICT_NAME_NC "qrk-gpio-restrict-nc"
++#define GPIO_RESTRICT_NAME_SC "qrk-gpio-restrict-sc"
++
++
++/* GPIO connected to Test Equipment */
++#define SUT_GPIO_NC_3 0x03
++#define SUT_GPIO_NC_4 0x04
++#define SUT_GPIO_NC_5 0x05
++#define SUT_GPIO_NC_6 0x06
++#define SUT_GPIO_SC_2 0x0A
++#define SUT_GPIO_SC_3 0x0B
++#define SUT_GPIO_SC_4 0x0C
++#define SUT_GPIO_SC_5 0x0D
++
++#define GPIO_NC_BITBANG_SPI_BUS 2
++#define GPIO_SC_BITBANG_SPI_BUS 3
++
++static struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .max_speed_hz = 50000000,
++ .bus_num = 0,
++ },
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .max_speed_hz = 50000000,
++ .bus_num = 1,
++ },
++};
++
++/*
++ * Define platform data for bitbanged SPI devices.
++ * Assign GPIO to SCK/MOSI/MISO
++ */
++static struct spi_gpio_platform_data spi_gpio_nc_data = {
++ .sck = SUT_GPIO_NC_3,
++ .mosi = SUT_GPIO_NC_4,
++ .miso = SUT_GPIO_NC_5,
++ .num_chipselect = 1,
++};
++static struct spi_gpio_platform_data spi_gpio_sc_data = {
++ .sck = SUT_GPIO_SC_2,
++ .mosi = SUT_GPIO_SC_3,
++ .miso = SUT_GPIO_SC_4,
++ .num_chipselect = 1,
++};
++
++/*
++ * Board information for bitbanged SPI devices.
++ */
++static const struct spi_board_info spi_gpio_nc_bi[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 1000,
++ .bus_num = GPIO_NC_BITBANG_SPI_BUS,
++ .mode = SPI_MODE_0,
++ .platform_data = &spi_gpio_nc_data,
++ /* Assign GPIO to CS */
++ .controller_data = (void *)SUT_GPIO_NC_6,
++ },
++};
++static const struct spi_board_info spi_gpio_sc_bi[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 1000,
++ .bus_num = GPIO_SC_BITBANG_SPI_BUS,
++ .mode = SPI_MODE_0,
++ .platform_data = &spi_gpio_sc_data,
++ /* Assign GPIO to CS */
++ .controller_data = (void *)SUT_GPIO_SC_5,
++ },
++};
++
++static struct platform_device spi_gpio_nc_pd = {
++ .name = "spi_gpio",
++ .id = GPIO_NC_BITBANG_SPI_BUS,
++ .dev = {
++ .platform_data = &spi_gpio_nc_data,
++ },
++};
++
++static struct platform_device spi_gpio_sc_pd = {
++ .name = "spi_gpio",
++ .id = GPIO_SC_BITBANG_SPI_BUS,
++ .dev = {
++ .platform_data = &spi_gpio_sc_data,
++ },
++};
++
++/**
++ * intel_qrk_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Clanton Peak platform
++ */
++static int intel_qrk_spi_add_onboard_devs(void)
++{
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++static int register_bitbanged_spi(int nc)
++{
++ int ret = 0;
++
++ ret = platform_device_register(nc ? &spi_gpio_nc_pd : &spi_gpio_sc_pd);
++ if (ret)
++ goto err;
++
++ ret = spi_register_board_info(nc ? spi_gpio_nc_bi : spi_gpio_sc_bi,
++ nc ? ARRAY_SIZE(spi_gpio_nc_bi) :
++ ARRAY_SIZE(spi_gpio_sc_bi));
++ if (ret)
++ goto err_unregister;
++
++ return 0;
++
++err_unregister:
++ platform_device_unregister(nc ? &spi_gpio_nc_pd : &spi_gpio_sc_pd);
++err:
++ return ret;
++}
++
++static int intel_qrk_gpio_restrict_probe_nc(struct platform_device *pdev)
++{
++ return register_bitbanged_spi(1);
++}
++
++static int intel_qrk_gpio_restrict_probe_sc(struct platform_device *pdev)
++{
++ return register_bitbanged_spi(0);
++}
++
++static struct platform_driver gpio_restrict_pdriver_nc = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME_NC,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_gpio_restrict_probe_nc,
++};
++
++static struct platform_driver gpio_restrict_pdriver_sc = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME_SC,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_gpio_restrict_probe_sc,
++};
++
++static int intel_qrk_plat_clanton_peak_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ ret = platform_driver_register(&gpio_restrict_pdriver_nc);
++ if (ret) {
++ pr_err("%s: couldn't register %s platform driver\n",
++ __func__, gpio_restrict_pdriver_nc.driver.name);
++ }
++
++ ret = platform_driver_register(&gpio_restrict_pdriver_sc);
++ if (ret) {
++ pr_err("%s: couldn't register %s platform driver\n",
++ __func__, gpio_restrict_pdriver_sc.driver.name);
++ }
++
++ return intel_qrk_spi_add_onboard_devs();
++}
++
++static int intel_qrk_plat_clanton_peak_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver clanton_peak_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_plat_clanton_peak_probe,
++ .remove = intel_qrk_plat_clanton_peak_remove,
++};
++
++module_platform_driver(clanton_peak_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Clanton Peak BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_plat_cross_hill.c
+@@ -0,0 +1,392 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * CrossHill board entry point
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "CrossHill"
++#define GPIO_RESTRICT_NAME_NC "qrk-gpio-restrict-nc"
++#define GPIO_RESTRICT_NAME_SC "qrk-gpio-restrict-sc"
++
++/*
++ * GPIO numbers to use for reading 4-bit Blackburn Peak SPI daughterboard ID
++ */
++#define SPI_BPEAK_RESET_GPIO 4
++#define SPI_BPEAK_ID0_GPIO 3
++#define SPI_BPEAK_ID1_GPIO 2
++#define SPI_BPEAK_ID2_GPIO 15
++#define SPI_BPEAK_ID3_GPIO 14
++
++static int nc_gpio_reg;
++static int sc_gpio_reg;
++
++static int cross_hill_probe;
++
++/*
++ * Blackburn Peak SPI daughterboard ID values
++ */
++enum {
++ QRK_SPI_BPEAK_ID_ZB_TI = 0xA,
++ QRK_SPI_BPEAK_ID_ZB_DIGI,
++ QRK_SPI_BPEAK_ID_ZB_INFR_NXP,
++ QRK_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL,
++ QRK_SPI_BPEAK_ID_ADC_MAXIM,
++ QRK_SPI_BPEAK_ID_NONE
++};
++
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
++};
++
++/******************************************************************************
++ * Maxim 78M6610+LMU SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/max78m6610_lmu.h"
++
++static const struct max78m6610_lmu_platform_data max78m6610_lmu_pdata = {
++ .reset_gpio = SPI_BPEAK_RESET_GPIO,
++};
++
++/******************************************************************************
++ * 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,
++};
++
++static struct pxa2xx_spi_chip qrk_ffrd_spi_1_cs_1 = {
++ .gpio_cs = 11,
++};
++
++static struct spi_board_info spi_generic_devs[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 50000000,
++ .platform_data = NULL,
++ .mode = SPI_MODE_0,
++ .bus_num = 1,
++ .chip_select = 0,
++ .controller_data = &qrk_ffrd_spi_1_cs_0,
++ },
++
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 50000000,
++ .platform_data = NULL,
++ .mode = SPI_MODE_0,
++ .bus_num = 1,
++ .chip_select = 1,
++ .controller_data = &qrk_ffrd_spi_1_cs_1,
++ },
++
++};
++
++static struct spi_board_info spi_energy_adc_devs[] = {
++ {
++ .modalias = "max78m6610_lmu",
++ .max_speed_hz = 2000000,
++ .platform_data = &max78m6610_lmu_pdata,
++ .mode = SPI_MODE_3,
++ .bus_num = 1,
++ .chip_select = 0,
++ .controller_data = &qrk_ffrd_spi_1_cs_0,
++ },
++};
++
++
++
++/**
++ * intel_qrk_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Cross Hill platform
++ */
++static int intel_qrk_spi_add_onboard_devs(void)
++{
++ struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &qrk_ffrd_spi_0_cs_0,
++ },
++ };
++
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++
++/**
++ * intel_qrk_spi_get_bpeak_id
++ *
++ * @param bpeak_id: The Blackburn Peak SPI ID obtained from the daughterboard
++ * @return 0 on success or standard errnos on failure
++ *
++ * Reads an ID from GPIO-connected pins on Blackburn peak SPI daughterboard
++ */
++static int intel_qrk_spi_get_bpeak_id(u8 *bpeak_id)
++{
++ int ret = 0;
++ struct gpio spi_bpeak_id_gpios[] = {
++ {
++ SPI_BPEAK_RESET_GPIO,
++ GPIOF_OUT_INIT_HIGH,
++ "spi_bpeak_reset"
++ },
++ {
++ SPI_BPEAK_ID0_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id0"
++ },
++ {
++ SPI_BPEAK_ID1_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id1"
++ },
++ {
++ SPI_BPEAK_ID2_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id2"
++ },
++ {
++ SPI_BPEAK_ID3_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id3"
++ }
++ };
++
++ /*
++ * Read a 4-bit ID value from ID GPIO inputs, which are only valid
++ * while a RESET GPIO output is asserted (active-low)
++ */
++ ret = gpio_request_array(spi_bpeak_id_gpios,
++ ARRAY_SIZE(spi_bpeak_id_gpios));
++ if (ret) {
++ pr_err("%s: Failed to allocate Blackburn Peak ID GPIO pins\n",
++ __func__);
++ return ret;
++ }
++
++ gpio_set_value(SPI_BPEAK_RESET_GPIO, 0);
++ *bpeak_id =
++ (gpio_get_value(SPI_BPEAK_ID3_GPIO) ? 1 << 3 : 0) |
++ (gpio_get_value(SPI_BPEAK_ID2_GPIO) ? 1 << 2 : 0) |
++ (gpio_get_value(SPI_BPEAK_ID1_GPIO) ? 1 << 1 : 0) |
++ (gpio_get_value(SPI_BPEAK_ID0_GPIO) ? 1 : 0);
++ gpio_set_value(SPI_BPEAK_RESET_GPIO, 1);
++
++ gpio_free_array(spi_bpeak_id_gpios,
++ ARRAY_SIZE(spi_bpeak_id_gpios));
++
++ return 0;
++}
++
++/**
++ * intel_qrk_spi_add_bpeak_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers SPI device(s) indicated by the ID value obtained from a
++ * Blackburn Peak SPI daughterboard
++ */
++static int intel_qrk_spi_add_bpeak_devs(void)
++{
++ u8 spi_bpeak_id = 0;
++ int ret = 0;
++
++ ret = intel_qrk_spi_get_bpeak_id(&spi_bpeak_id);
++ if (ret) {
++ pr_err("%s: failed to obtain Blackburn Peak ID\n",
++ __func__);
++ return ret;
++ }
++
++ switch (spi_bpeak_id) {
++
++ case QRK_SPI_BPEAK_ID_NONE:
++ break;
++
++ case QRK_SPI_BPEAK_ID_ADC_MAXIM:
++ {
++ return spi_register_board_info(spi_energy_adc_devs,
++ ARRAY_SIZE(spi_energy_adc_devs));
++ }
++ case QRK_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL:
++ {
++ pr_debug("QRK_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL.\n");
++ return spi_register_board_info(spi_generic_devs,
++ ARRAY_SIZE(spi_generic_devs));
++ }
++ case QRK_SPI_BPEAK_ID_ZB_DIGI:
++ {
++ pr_debug("QRK_SPI_BPEAK_ID_ZB_DIGI load.\n");
++ return spi_register_board_info(spi_generic_devs,
++ ARRAY_SIZE(spi_generic_devs));
++
++ }
++ default:
++ pr_err("%s: Unsupported Blackburn Peak SPI ID %u\n",
++ __func__, spi_bpeak_id);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++/** intel_qrk_spi_devs_addon
++ *
++ * addon spi device when gpio support in place
++ */
++static int intel_qrk_spi_devs_addon(void)
++{
++ int ret = 0;
++
++ if (cross_hill_probe != 1) {
++
++ ret = intel_qrk_spi_add_onboard_devs();
++ if (ret)
++ return ret;
++
++ ret = intel_qrk_spi_add_bpeak_devs();
++
++ cross_hill_probe = 1;
++ }
++
++ return ret;
++}
++
++/**
++ * intel_qrk_gpio_restrict_probe_nc
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_qrk_gpio_restrict_probe_nc(struct platform_device *pdev)
++{
++ int ret;
++ nc_gpio_reg = 1;
++
++ if (nc_gpio_reg == 1 && sc_gpio_reg == 1) {
++ ret = intel_qrk_spi_devs_addon();
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++/**
++ * intel_qrk_gpio_restrict_probe_sc
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_qrk_gpio_restrict_probe_sc(struct platform_device *pdev)
++{
++ int ret;
++ sc_gpio_reg = 1;
++
++ if (nc_gpio_reg == 1 && sc_gpio_reg == 1) {
++ ret = intel_qrk_spi_devs_addon();
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static struct platform_driver gpio_restrict_pdriver_nc = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME_NC,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_gpio_restrict_probe_nc,
++};
++
++static struct platform_driver gpio_restrict_pdriver_sc = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME_SC,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_gpio_restrict_probe_sc,
++};
++
++static int intel_qrk_plat_cross_hill_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ ret = platform_driver_register(&gpio_restrict_pdriver_nc);
++ if (ret)
++ return ret;
++
++ return platform_driver_register(&gpio_restrict_pdriver_sc);
++}
++
++static int intel_qrk_plat_cross_hill_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver qrk_cross_hill_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_plat_cross_hill_probe,
++ .remove = intel_qrk_plat_cross_hill_remove,
++};
++
++module_platform_driver(qrk_cross_hill_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Cross Hill BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_plat_galileo.c
+@@ -0,0 +1,398 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * 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/cy8c9540a.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/at24.h>
++
++#define DRIVER_NAME "Galileo"
++#define GPIO_RESTRICT_NAME "qrk-gpio-restrict-sc"
++#define LPC_SCH_SPINAME "spi-lpc-sch"
++
++/* GPIO line used to detect the LSB of the Cypress i2c address */
++#define GPIO_CYPRESS_A0 7
++/* GPIO line Cypress interrupts are routed to (in S0 power state) */
++#define GPIO_CYPRESS_INT_S0 13
++/* GPIO line Cypress interrupts are routed to (in S3 power state) */
++#define GPIO_CYPRESS_INT_S3 2
++
++/* Cypress i2c address depending on A0 value */
++#define CYPRESS_ADDR_A0_1 0x20
++#define CYPRESS_ADDR_A0_0 0x21
++#define EEPROM_ADDR_A0_1 0x50
++#define EEPROM_ADDR_A0_0 0x51
++
++/******************************************************************************
++ * Cypress I/O Expander Platform Data
++ ******************************************************************************/
++static struct cy8c9540a_pdata cy8c9540a_platform_data = {
++ .por_default = {
++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Output */
++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Int mask */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* PWM */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Inversion */
++ 0xe0, 0xe0, 0xff, 0xf3, 0x00, 0xff, 0xff, 0xff, /* Direction */
++ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* P0 drive */
++ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* P1 drive */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P2 drive */
++ 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, /* P3 drive */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* P4 drive */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P5 drive */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P6 drive */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P7 drive */
++ 0x00, 0xff, 0x00, /* PWM0 */
++ 0x00, 0xff, 0x00, /* PWM1 */
++ 0x00, 0xff, 0x00, /* PWM2 */
++ 0x00, 0xff, 0x00, /* PWM3 */
++ 0x00, 0xff, 0x00, /* PWM4 */
++ 0x00, 0xff, 0x00, /* PWM5 */
++ 0x00, 0xff, 0x00, /* PWM6 */
++ 0x00, 0xff, 0x00, /* PWM7 */
++ 0x00, 0xff, 0x00, /* PWM8 */
++ 0x00, 0xff, 0x00, /* PWM9 */
++ 0x00, 0xff, 0x00, /* PWM10 */
++ 0x00, 0xff, 0x00, /* PWM11 */
++ 0x00, 0xff, 0x00, /* PWM12 */
++ 0x00, 0xff, 0x00, /* PWM13 */
++ 0x00, 0xff, 0x00, /* PWM14 */
++ 0x00, 0xff, 0x00, /* PWM15 */
++ 0xff, /* PWM CLKdiv */
++ 0x02, /* EEPROM en */
++ 0x00 /* CRC */
++ },
++ .pwm2gpio_mapping = {
++ CY8C9540A_PWM_UNUSED,
++ 3,
++ CY8C9540A_PWM_UNUSED,
++ 2,
++ 9,
++ 1,
++ 8,
++ 0,
++ },
++ .gpio_base = 16,
++ .pwm_base = 0,
++ .irq_base = 64,
++};
++
++/* Cypress expander requires i2c master to operate @100kHz 'standard mode' */
++static struct intel_qrk_gip_pdata gip_pdata = {
++ .i2c_std_mode = 1,
++};
++static struct intel_qrk_gip_pdata *galileo_gip_get_pdata(void)
++{
++ return &gip_pdata;
++}
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
++};
++
++static struct at24_platform_data at24_platform_data = {
++ .byte_len = (11 * 1024),
++ .page_size = 1,
++ .flags = AT24_FLAG_ADDR16,
++};
++
++/******************************************************************************
++ * Intel Izmir i2c clients
++ ******************************************************************************/
++static struct i2c_board_info probed_i2c_cypress = {
++ .platform_data = &cy8c9540a_platform_data,
++};
++static struct i2c_board_info probed_i2c_eeprom = {
++ .platform_data = &at24_platform_data,
++};
++static struct i2c_adapter *i2c_adap;
++static const unsigned short cypress_i2c_addr[] =
++ { CYPRESS_ADDR_A0_1, CYPRESS_ADDR_A0_0, I2C_CLIENT_END };
++static const unsigned short eeprom_i2c_addr[] =
++ { EEPROM_ADDR_A0_1, EEPROM_ADDR_A0_0, I2C_CLIENT_END };
++
++/******************************************************************************
++ * 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 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 = ilb_partitions,
++ .nr_parts = ARRAY_SIZE(ilb_partitions),
++};
++
++static struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "m25p80",
++ .platform_data = &ilb_flash,
++ .bus_num = LPC_SCH_SPI_BUS_ID,
++ .chip_select = 0,
++ },
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &qrk_ffrd_spi_0_cs_0,
++ },
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .controller_data = &qrk_ffrd_spi_1_cs_0,
++ .max_speed_hz = 50000000,
++ .bus_num = 1,
++ },
++};
++
++static struct gpio reserved_gpios[] = {
++ {
++ GPIO_CYPRESS_A0,
++ GPIOF_IN,
++ "cy8c9540a-a0",
++ },
++ {
++ GPIO_CYPRESS_INT_S0,
++ GPIOF_IN,
++ "cy8c9540a-int-s0",
++ },
++ {
++ GPIO_CYPRESS_INT_S3,
++ GPIOF_IN,
++ "cy8c9540a-int-s3",
++ },
++};
++
++static int eeprom_i2c_probe(struct i2c_adapter *adap, unsigned short addr)
++{
++ if (gpio_get_value(GPIO_CYPRESS_A0) && EEPROM_ADDR_A0_1 == addr)
++ return 1;
++ if (!gpio_get_value(GPIO_CYPRESS_A0) && EEPROM_ADDR_A0_0 == addr)
++ return 1;
++ return 0;
++}
++static int cypress_i2c_probe(struct i2c_adapter *adap, unsigned short addr)
++{
++ if (gpio_get_value(GPIO_CYPRESS_A0) && CYPRESS_ADDR_A0_1 == addr)
++ return 1;
++ if (!gpio_get_value(GPIO_CYPRESS_A0) && CYPRESS_ADDR_A0_0 == addr)
++ return 1;
++ return 0;
++}
++
++/**
++ * 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)
++{
++
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++
++/**
++ * intel_qrk_gpio_restrict_probe
++ *
++ * Register devices that depend on GPIOs.
++ * Note this function makes extensive use of the probe deferral mechanism:
++ * gpio_request() for a GPIO that is not yet available returns
++ * -EPROBE_DEFER.
++ */
++static int intel_qrk_gpio_restrict_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ struct i2c_client *cypress = NULL, *eeprom = NULL;
++ static int spi_done;
++ static int gpios_done;
++
++ if (spi_done)
++ goto gpios;
++
++ ret = intel_qrk_spi_add_onboard_devs();
++ if (ret)
++ goto end;
++
++ spi_done = 1;
++
++gpios:
++ if (gpios_done)
++ goto i2c;
++
++ ret = gpio_request_array(reserved_gpios, ARRAY_SIZE(reserved_gpios));
++ if (ret)
++ goto end;
++
++ probed_i2c_cypress.irq = gpio_to_irq(GPIO_CYPRESS_INT_S0);
++
++ gpios_done = 1;
++
++i2c:
++ i2c_adap = i2c_get_adapter(0);
++ if (NULL == i2c_adap) {
++ pr_info("%s: i2c adapter not ready yet. Deferring..\n",
++ __func__);
++ ret = -EPROBE_DEFER;
++ goto end;
++ }
++ strlcpy(probed_i2c_cypress.type, "cy8c9540a", I2C_NAME_SIZE);
++ cypress = i2c_new_probed_device(i2c_adap, &probed_i2c_cypress,
++ cypress_i2c_addr, cypress_i2c_probe);
++ strlcpy(probed_i2c_eeprom.type, "at24", I2C_NAME_SIZE);
++ eeprom = i2c_new_probed_device(i2c_adap, &probed_i2c_eeprom,
++ eeprom_i2c_addr, eeprom_i2c_probe);
++ i2c_put_adapter(i2c_adap);
++
++ if (NULL == cypress || NULL == eeprom) {
++ pr_err("%s: can't probe Cypress Expander\n", __func__);
++ ret = -ENODEV;
++ goto end;
++ }
++
++end:
++ 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_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ /* Assign GIP driver handle for board-specific settings */
++ intel_qrk_gip_get_pdata = galileo_gip_get_pdata;
++
++ /* gpio */
++ ret = platform_driver_register(&gpio_restrict_pdriver);
++ if (ret)
++ goto end;
++
++#if 0
++ /* legacy SPI - TBD */
++ ret = platform_driver_register(&intel_qrk_plat_galileo_lpcspi_pdriver);
++ if (ret)
++ goto end;
++#endif
++end:
++ return ret;
++}
++
++static int intel_qrk_plat_galileo_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_probe,
++ .remove = intel_qrk_plat_galileo_remove,
++};
++
++module_platform_driver(qrk_galileo_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Galileo 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..5e94b4b
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_plat_kips_bay.c
+@@ -0,0 +1,176 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "KipsBay"
++#define GPIO_RESTRICT_NAME "qrk-gpio-restrict-sc"
++
++static int gpio_cs = 1;
++
++module_param(gpio_cs, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(gpio_cs, "Enable GPIO chip-select for SPI channel 1");
++
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
++};
++
++/******************************************************************************
++ * 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,
++};
++
++static struct spi_board_info spi0_onboard_devs[] = {
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .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 Kips Bay 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));
++}
++
++
++/**
++ * intel_qrk_gpio_restrict_probe
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_qrk_gpio_restrict_probe(struct platform_device *pdev)
++{
++ return intel_qrk_spi_add_onboard_devs();
++}
++
++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_kips_bay_probe(struct platform_device *pdev)
++{
++ return platform_driver_register(&gpio_restrict_pdriver);
++}
++
++static int intel_qrk_plat_kips_bay_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver qrk_kips_bay_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_plat_kips_bay_probe,
++ .remove = intel_qrk_plat_kips_bay_remove,
++};
++
++module_platform_driver(qrk_kips_bay_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Kips Bay BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_sb.c
+@@ -0,0 +1,253 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark side-band driver
++ *
++ * Thread-safe sideband read/write routine.
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2012
++ */
++
++#include <linux/errno.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spinlock.h>
++#include <linux/pci.h>
++#include "intel_qrk_imr.h"
++
++#define INTEL_QRK_SB_CMD_ADDR (0x000000D0)
++#define INTEL_QRK_SB_DATA_ADDR (0x000000D4)
++
++#define INTEL_QRK_SB_MCR_SHIFT (24)
++#define INTEL_QRK_SB_PORT_SHIFT (16)
++#define INTEL_QRK_SB_REG_SHIFT (8)
++#define INTEL_QRK_SB_BYTEEN (0xF0) /* enable all 32 bits */
++
++/* Simple structure for module */
++struct intel_qrk_sb_dev{
++ struct pci_dev * pdev;
++ spinlock_t slock;
++ u8 initialized;
++};
++
++static struct intel_qrk_sb_dev sb_dev = {
++ .initialized = 0
++};
++
++/* Dependant drivers */
++static struct platform_device pdev [] = {
++ {
++ .name = "intel-qrk-esram",
++ },
++ {
++ .name = "intel-qrk-ecc",
++ },
++ {
++ .name = "intel-qrk-thrm",
++ },
++};
++
++/**
++ * intel_qrk_sb_read_reg
++ *
++ * @param qrk_sb_id: Sideband identifier
++ * @param command: Command to send to destination identifier
++ * @param reg: Target register w/r to qrk_sb_id
++ * @return nothing
++ *
++ * Utility function to allow thread-safe read of side-band
++ * command - can be different read op-code types - which is why we don't
++ * hard-code this value directly into msg
++ */
++void intel_qrk_sb_read_reg(qrk_sb_id id, u8 cmd, u8 reg, u32 *data, u8 lock)
++{
++ u32 msg = (cmd << INTEL_QRK_SB_MCR_SHIFT) |
++ ((id << INTEL_QRK_SB_PORT_SHIFT) & 0xFF0000)|
++ ((reg << INTEL_QRK_SB_REG_SHIFT) & 0xFF00)|
++ INTEL_QRK_SB_BYTEEN;
++
++ if(data == NULL)
++ return;
++
++ if (likely(lock == 1)) {
++ spin_lock(&sb_dev.slock);
++ }
++
++ pci_write_config_dword(sb_dev.pdev, INTEL_QRK_SB_CMD_ADDR, msg);
++ pci_read_config_dword(sb_dev.pdev, INTEL_QRK_SB_DATA_ADDR, data);
++
++ if(likely(lock == 1)){
++ spin_unlock(&sb_dev.slock);
++ }
++
++}
++EXPORT_SYMBOL(intel_qrk_sb_read_reg);
++
++/**
++ * intel_qrk_sb_write_reg
++ *
++ * @param qrk_sb_id: Sideband identifier
++ * @param command: Command to send to destination identifier
++ * @param reg: Target register w/r to qrk_sb_id
++ * @return nothing
++ *
++ * Utility function to allow thread-safe write of side-band
++ */
++void intel_qrk_sb_write_reg(qrk_sb_id id, u8 cmd, u8 reg, u32 data, u8 lock)
++{
++ u32 msg = (cmd << INTEL_QRK_SB_MCR_SHIFT) |
++ ((id << INTEL_QRK_SB_PORT_SHIFT) & 0xFF0000)|
++ ((reg << INTEL_QRK_SB_REG_SHIFT) & 0xFF00)|
++ INTEL_QRK_SB_BYTEEN;
++
++ if(likely(lock == 1)){
++ spin_lock(&sb_dev.slock);
++ }
++
++ pci_write_config_dword(sb_dev.pdev, INTEL_QRK_SB_DATA_ADDR, data);
++ pci_write_config_dword(sb_dev.pdev, INTEL_QRK_SB_CMD_ADDR, msg);
++
++ if(likely(lock == 1)){
++ spin_unlock(&sb_dev.slock);
++ }
++}
++EXPORT_SYMBOL(intel_qrk_sb_write_reg);
++
++/**
++ * intel_qrk_sb_runfn_lock
++ *
++ * @param fn: Callback function - which requires side-band spinlock and !irq
++ * @param arg: Callback argument
++ * @return 0 on success < 0 on failure
++ *
++ * Runs the given function pointer inside of a call to the local spinlock using
++ * spin_lock_irqsave/spin_unlock_irqrestore. Needed for the eSRAMv1 driver to
++ * guarantee atomicity, but, available to any other user of sideband provided
++ * rules are respected.
++ * Rules:
++ * fn may not sleep
++ * fn may not change the state of irqs
++ */
++int intel_qrk_sb_runfn_lock(int (*fn)( void * arg ), void * arg)
++{
++ unsigned long flags = 0;
++ int ret = 0;
++
++ if(unlikely(fn == NULL)){
++ return -EINVAL;
++ }
++
++ /* Get spinlock with IRQs off */
++ spin_lock_irqsave(&sb_dev.slock, flags);
++
++ /* Run function atomically */
++ ret = fn(arg);
++
++ /* Release lock */
++ spin_unlock_irqrestore(&sb_dev.slock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(intel_qrk_sb_runfn_lock);
++
++/**
++ * sb_probe
++ *
++ * @param dev: the PCI device matching
++ * @param id: entry in the match table
++ * @return 0
++ *
++ * Callback from PCI layer when dev/vendor ids match.
++ * Sets up necessary resources
++ */
++static int intel_qrk_sb_probe(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ int i = 0;
++
++ /* Init struct */
++ memset(&sb_dev, 0x00, sizeof(sb_dev));
++
++ /* Hook device */
++ sb_dev.pdev = dev;
++
++ /* Init locking structures */
++ spin_lock_init(&sb_dev.slock);
++
++ /* Set state */
++ sb_dev.initialized = 1;
++
++ /* Register side-band sub-ordinate drivers */
++ for (i = 0; i < sizeof(pdev)/sizeof(struct platform_device); i++){
++ /* Register side-band sub-ordinate drivers */
++ platform_device_register(&pdev[i]);
++ }
++ pr_info("Intel Quark side-band driver registered\n");
++
++ /* Switch off boot-time IMRs nice and early */
++ return intel_qrk_imr_init(dev->device);
++}
++
++/**
++ * sb_remove
++ *
++ * @param pdev: PCI device
++ * @return nothing
++ *
++ * Callback from PCI sub-system upon PCI dev removal
++ */
++static void intel_qrk_sb_remove(struct pci_dev *pdev)
++{
++}
++
++/* Quark hardware */
++struct pci_device_id intel_qrk_sb_ids[] = {
++ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_X1000_HOST_BRIDGE), 0},
++ { PCI_VDEVICE(INTEL, 0x12C0), 0},
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(pci, intel_qrk_sb_ids);
++
++/* PCI callbacks */
++static struct pci_driver intel_qrk_sb_driver = {
++ .name = "intel_qrk_sb",
++ .id_table = intel_qrk_sb_ids,
++ .probe = intel_qrk_sb_probe,
++ .remove = intel_qrk_sb_remove,
++};
++
++/**
++ * intel_qrk_sb_init
++ *
++ * Module entry point
++ */
++static int __init intel_qrk_sb_init(void)
++{
++ return pci_register_driver(&intel_qrk_sb_driver);
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Quark SOC side-band driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++/* Initialise early since other drivers eSRAM, DRAM ECC and thermal depend */
++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
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_qrk_thermal.c
+@@ -0,0 +1,360 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark Thermal driver
++ */
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/intel_qrk_sb.h>
++#include <linux/list.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/thermal.h>
++#include <linux/timer.h>
++
++#define DRIVER_NAME "intel-qrk-thrm"
++
++/* Definition of register locations for thermal management */
++#define THRM_CTRL_REG (0x80) /* Thermal control */
++#define THRM_MODE_REG (0xB0) /* Thermal mode */
++#define THRM_MODE_SENSOR_EN (0x00008000) /* Thermal mode sensor enable */
++#define THRM_TEMP_REG (0xB1) /* Thermal sensor temperature */
++#define THRM_TRPCLR_REG (0xB2) /* Catastropic/Hot trip/clear */
++#define THRM_AUXTRP_REG (0xB3) /* Aux0-Aux3 trip point */
++#define THRM_AUXCLR_REG (0xB4) /* Aux0-Aux3 clear trip */
++#define THRM_STATUS_REG (0xB5) /* Thermal sensor status */
++#define THRM_TRIPBEHAVE_REG (0xB6) /* Trip point behavior */
++#define THRM_MSIADDR_REG (0xC5) /* Thermal MSI addres reg */
++#define THRM_MSIDATA_REG (0xC6) /* Thermal MSI data reg */
++#define THRM_CTRL_READ (0x10) /* Config reg */
++#define THRM_CTRL_WRITE (0x11) /* Config reg */
++
++#define SOC_TSENSOR_REG (0x34)
++#define SOC_TSENSOR_RST (0x00000001)
++#define SOC_CTRL_READ (0x06)
++#define SOC_CTRL_WRITE (0x07)
++
++
++#define THRM_ZONE_COUNT 2 /* Only hot/critical relevant */
++#define ACTIVE_INTERVAL (1000)
++#define IDLE_INTERVAL (20000)
++#define MCELSIUS(x) ((x) * 1000)
++
++/* CPU Zone information */
++#define CATASTROPIC_ZONE 0
++#define HOT_ZONE 1
++#define AUX0_ZONE 2 /* Unused */
++#define AUX1_ZONE 3 /* Unused */
++#define AUX2_ZONE 4 /* Unused */
++#define AUX3_ZONE 5 /* Unused */
++#define MIN_USED_ZONE CATASTROPIC_ZONE
++#define MAX_USED_ZONE HOT_ZONE
++/*
++ * Default catastrophic/hot trip values - in degrees celsius
++ * Maximum temperature is 105 degrees
++ */
++#define CRIT_TEMP 104
++#define HOT_TEMP 95
++#define RAW2CELSIUS_DIFF 50
++
++static int driver_enable = 1;
++module_param(driver_enable, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(driver_enable, "Disable Thermal Driver Polling");
++
++/* Shorten fn names to fit 80 char limit */
++#ifndef sb_read
++#define sb_read intel_qrk_sb_read_reg
++#endif
++#ifndef sb_write
++#define sb_write intel_qrk_sb_write_reg
++#endif
++
++struct intel_qrk_therm_zone {
++ enum thermal_trip_type type;
++ int trip_value;
++};
++
++/**
++ * struct intel_qrk_thermal_dev
++ *
++ */
++struct intel_qrk_thermal_dev {
++ enum thermal_device_mode mode;
++ struct intel_qrk_therm_zone tzone[THRM_ZONE_COUNT];
++ struct mutex lock;
++ struct platform_device *pldev; /* Platform device */
++ struct thermal_zone_device *therm_dev; /* Thermal device */
++};
++
++static struct intel_qrk_thermal_dev qrk_tdev;
++
++/******************************************************************************
++ * Thermal API implementation
++ ******************************************************************************/
++
++/**
++ * get_temp
++ *
++ * @param tz: Thermal zone descriptor
++ *
++ * Get the current temperature
++ * We have exactly one thermal zone/sensor
++ * Value passed is an unsigned long - our sensor reports up to -50 celsius so we
++ * just clip at zero if the temperature is negative.
++ */
++static int intel_qrk_thermal_get_temp(struct thermal_zone_device *tz,
++ unsigned long *temp)
++{
++ sb_read(SB_ID_THERMAL, THRM_CTRL_READ, THRM_TEMP_REG, (u32 *)temp, 1);
++ *temp -= RAW2CELSIUS_DIFF;
++
++ /* Clip to unsigned output value if sensor is reporting sub-zero */
++ if ((int)*temp < 0)
++ *temp = 0;
++
++ *temp = MCELSIUS(*temp&0x000000FF);
++
++ return 0;
++}
++
++/**
++ * get_trend
++ *
++ * Wears good clothes
++ */
++static int intel_qrk_thermal_get_trend(struct thermal_zone_device *tz,
++ int trip, enum thermal_trend *trend)
++{
++ if (tz->temperature >= trip)
++ *trend = THERMAL_TREND_RAISING;
++ else
++ *trend = THERMAL_TREND_DROPPING;
++
++ return 0;
++}
++
++/**
++ * intel_qrk_thermal_get_mode
++ *
++ * Get the mode
++ */
++static int intel_qrk_thermal_get_mode(struct thermal_zone_device *tz,
++ enum thermal_device_mode *mode)
++{
++ mutex_lock(&qrk_tdev.lock);
++ *mode = qrk_tdev.mode;
++ mutex_unlock(&qrk_tdev.lock);
++
++ return 0;
++}
++
++/**
++ * intel_qrk_thermal_set_mode
++ *
++ * Set the mode
++ */
++static int intel_qrk_thermal_set_mode(struct thermal_zone_device *tz,
++ enum thermal_device_mode mode)
++{
++ mutex_lock(&qrk_tdev.lock);
++
++ if (mode == THERMAL_DEVICE_ENABLED)
++ qrk_tdev.therm_dev->polling_delay = IDLE_INTERVAL;
++ else
++ qrk_tdev.therm_dev->polling_delay = 0;
++ qrk_tdev.mode = mode;
++
++ mutex_unlock(&qrk_tdev.lock);
++
++ thermal_zone_device_update(qrk_tdev.therm_dev);
++ pr_info("thermal polling set for duration=%d msec\n",
++ qrk_tdev.therm_dev->polling_delay);
++ return 0;
++}
++
++/**
++ * intel_qrk_thermal_get_trip_type
++ *
++ * Get trip type
++ */
++static int intel_qrk_thermal_get_trip_type(struct thermal_zone_device *tz,
++ int trip, enum thermal_trip_type *type)
++{
++ if (trip < MIN_USED_ZONE || trip > MAX_USED_ZONE)
++ return -EINVAL;
++
++ *type = qrk_tdev.tzone[trip].type;
++ return 0;
++}
++
++/**
++ * intel_qrk_thermal_get_trip_temp
++ *
++ * Get trip temp
++ */
++static int intel_qrk_thermal_get_trip_temp(struct thermal_zone_device *tz,
++ int trip, unsigned long *temp)
++{
++ if (trip < MIN_USED_ZONE || trip > MAX_USED_ZONE)
++ return -EINVAL;
++
++ /* Convert the temperature into millicelsius */
++ *temp = qrk_tdev.tzone[trip].trip_value;
++
++ return 0;
++}
++
++/**
++ * intel_qrk_thermal_get_trip_type
++ *
++ * Get trip temp
++ */
++static int intel_qrk_thermal_get_crit_temp(struct thermal_zone_device *tz,
++ unsigned long *temp)
++{
++ /* Critical zone */
++ *temp = qrk_tdev.tzone[CATASTROPIC_ZONE].trip_value;
++ return 0;
++}
++
++static struct thermal_zone_device_ops intel_qrk_thrm_dev_ops = {
++ .get_temp = intel_qrk_thermal_get_temp,
++ .get_trend = intel_qrk_thermal_get_trend,
++ .get_mode = intel_qrk_thermal_get_mode,
++ .set_mode = intel_qrk_thermal_set_mode,
++ .get_trip_type = intel_qrk_thermal_get_trip_type,
++ .get_trip_temp = intel_qrk_thermal_get_trip_temp,
++ .get_crit_temp = intel_qrk_thermal_get_crit_temp,
++};
++
++
++
++/**
++ * intel_qrk_init_zone
++ *
++ * Initialise a zone
++ */
++static void intel_qrk_thermal_init_zone(struct intel_qrk_therm_zone *tz,
++ enum thermal_trip_type type, int trip_value)
++{
++ tz->type = type;
++ tz->trip_value = MCELSIUS(trip_value);
++}
++
++/******************************************************************************
++ * Module Entry/Exit hooks
++ ******************************************************************************/
++
++/**
++ * intel_qrk_thermal_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This routine registers a thermal device with the kernel's thermal management
++ * sub-system
++ */
++static int intel_qrk_thermal_probe(struct platform_device *pdev)
++{
++ int err = 0;
++ int critical_temp = 0, hot_temp = 0;
++ uint32_t regval = 0;
++
++ if (driver_enable == 0)
++ return 0;
++
++ memset(&qrk_tdev, 0x00, sizeof(qrk_tdev));
++
++ critical_temp = CRIT_TEMP;
++ hot_temp = HOT_TEMP;
++
++ /* Enumerate zone type data */
++ memset(&qrk_tdev, 0x00, sizeof(qrk_tdev));
++ mutex_init(&qrk_tdev.lock);
++
++ /* Set initial state disabled */
++ qrk_tdev.mode = THERMAL_DEVICE_ENABLED;
++
++ intel_qrk_thermal_init_zone(&qrk_tdev.tzone[CATASTROPIC_ZONE],
++ THERMAL_TRIP_CRITICAL, critical_temp);
++ intel_qrk_thermal_init_zone(&qrk_tdev.tzone[HOT_ZONE],
++ THERMAL_TRIP_HOT, hot_temp);
++
++ /* Register a thermal zone */
++ qrk_tdev.therm_dev = thermal_zone_device_register(DRIVER_NAME,
++ THRM_ZONE_COUNT, 0, 0, &intel_qrk_thrm_dev_ops,
++ 0, IDLE_INTERVAL, ACTIVE_INTERVAL);
++
++ if (IS_ERR(qrk_tdev.therm_dev)) {
++ err = PTR_ERR(qrk_tdev.therm_dev);
++ return err;
++ }
++
++ /* Read the BIOS configured hardware catastrophic trip temp */
++ sb_read(SB_ID_THERMAL, THRM_CTRL_READ, THRM_TRPCLR_REG, &regval, 1);
++ regval = (regval & 0xff) - 50;
++
++ pr_info("THRM: critical reset %d c hot %d c hardware failover %d c\n",
++ critical_temp, hot_temp, regval);
++
++ return 0;
++}
++
++/**
++ * intel_qrk_thermal_remove
++ *
++ * @return 0 success < 0 failure
++ *
++ * Removes a platform device
++ */
++static int intel_qrk_thermal_remove(struct platform_device *pdev)
++{
++ if (qrk_tdev.therm_dev != NULL) {
++ thermal_zone_device_unregister(qrk_tdev.therm_dev);
++ return 0;
++ }
++ return -EINVAL;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_qrk_thermal_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_qrk_thermal_probe,
++ .remove = intel_qrk_thermal_remove,
++};
++
++module_platform_driver(intel_qrk_thermal_driver);
++
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Quark Thermal driver");
++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
+--- /dev/null
++++ b/include/linux/intel_qrk_sb.h
+@@ -0,0 +1,92 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark side-band driver
++ *
++ * Thread-safe sideband read/write routine.
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2012
++ */
++
++#ifndef __INTEL_QRK_SB_H__
++#define __INTEL_QRK_SB_H__
++
++#include <linux/types.h>
++
++#define PCI_DEVICE_ID_X1000_HOST_BRIDGE 0x0958
++
++typedef enum {
++ SB_ID_HUNIT = 0x03,
++ SB_ID_THERMAL = 0x04,
++ SB_ID_ESRAM = 0x05,
++ SB_ID_SOC = 0x31,
++}qrk_sb_id;
++
++/**
++ * intel_qrk_sb_read_reg
++ *
++ * @param qrk_sb_id: Sideband identifier
++ * @param command: Command to send to destination identifier
++ * @param reg: Target register w/r to qrk_sb_id
++ * @return nothing
++ *
++ * Utility function to allow thread-safe read of side-band
++ * command - can be different read op-code types - which is why we don't
++ * hard-code this value directly into msg
++ */
++void intel_qrk_sb_read_reg(qrk_sb_id id, u8 cmd, u8 reg, u32 *data, u8 lock);
++
++/**
++ * intel_qrk_sb_write_reg
++ *
++ * @param qrk_sb_id: Sideband identifier
++ * @param command: Command to send to destination identifier
++ * @param reg: Target register w/r to qrk_sb_id
++ * @return nothing
++ *
++ * Utility function to allow thread-safe write of side-band
++ */
++void intel_qrk_sb_write_reg(qrk_sb_id id, u8 cmd, u8 reg, u32 data, u8 lock);
++
++/**
++ * intel_qrk_sb_runfn_lock
++ *
++ * @param fn: Callback function - which requires side-band spinlock and !irq
++ * @param arg: Callback argument
++ * @return 0 on success < 0 on failure
++ *
++ * Runs the given function pointer inside of a call to the local spinlock using
++ * spin_lock_irqsave/spin_unlock_irqrestore. Needed for the eSRAMv1 driver to
++ * guarantee atomicity, but, available to any other user of sideband provided
++ * rules are respected.
++ * Rules:
++ * fn may not sleep
++ * fn may not change the state of irqs
++ */
++int intel_qrk_sb_runfn_lock(int (*fn)( void * arg ), void * arg);
++
++/**
++ * intel_qrk_sb_initialized
++ *
++ * False if sideband running on non-Quark system
++ */
++int intel_qrk_sb_initialized(void);
++
++#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
+--- /dev/null
++++ b/include/linux/platform_data/quark.h
+@@ -0,0 +1,44 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark platform data definition
++ */
++
++#ifndef _PDATA_QUARK_H
++#define _PDATA_QUARK_H
++
++typedef enum {
++ QUARK_PLAT_UNDEFINED = 0,
++ QUARK_EMULATION = 1,
++ QUARK_PEAK = 2,
++ KIPS_BAY = 3,
++ CROSS_HILL = 4,
++ QUARK_HILL = 5,
++ GALILEO = 6,
++}qrk_plat_id_t;
++
++typedef enum {
++ PLAT_DATA_ID = 1,
++ PLAT_DATA_SN = 2,
++ PLAT_DATA_MAC0 = 3,
++ PLAT_DATA_MAC1 = 4,
++}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
new file mode 100644
index 0000000..15b0ffd
--- /dev/null
+++ b/recipes-kernel/linux/files/0008-Quark-UART-quark.patch
@@ -0,0 +1,5894 @@
+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
+Subject: [PATCH 08/21] Quark UART
+
+---
+ drivers/dma/Kconfig | 6 +-
+ 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/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(-)
+ 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
+
+diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
+index d4c1218..9867547 100644
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -34,13 +34,13 @@ if DMADEVICES
+ comment "DMA Devices"
+
+ config INTEL_MID_DMAC
+- tristate "Intel MID DMA support for Peripheral DMA controllers"
++ tristate "Intel DMAC Moorsetown/Medfield/Quark DMA controllers"
+ depends on PCI && X86
+ select DMA_ENGINE
+ default n
+ help
+- Enable support for the Intel(R) MID DMA engine present
+- in Intel MID chipsets.
++ Enable support for the Intel(R) MID/Quark DMA engine present
++ in Intel MID chipsets and Quark SOC devices
+
+ Say Y here if you have such a chipset.
+
+diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
+index 7428fea..0ab1b45 100644
+--- a/drivers/dma/Makefile
++++ b/drivers/dma/Makefile
+@@ -5,6 +5,7 @@ obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
+ obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
+ obj-$(CONFIG_NET_DMA) += iovlock.o
+ obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
++intel_mid_dma-objs:= intel_mid_dma_core.o intel_qrk_dma_pci.o intel_mid_dma_pci.o
+ obj-$(CONFIG_DMATEST) += dmatest.o
+ obj-$(CONFIG_INTEL_IOATDMA) += ioat/
+ obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
+diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
+deleted file mode 100644
+index a0de82e..0000000
+--- a/drivers/dma/intel_mid_dma.c
++++ /dev/null
+@@ -1,1460 +0,0 @@
+-/*
+- * intel_mid_dma.c - Intel Langwell DMA Drivers
+- *
+- * Copyright (C) 2008-10 Intel Corp
+- * Author: Vinod Koul <vinod.koul@intel.com>
+- * The driver design is based on dw_dmac driver
+- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; version 2 of the License.
+- *
+- * This program is distributed in the hope that it will be useful, but
+- * WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License along
+- * with this program; if not, write to the Free Software Foundation, Inc.,
+- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+- *
+- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- *
+- *
+- */
+-#include <linux/pci.h>
+-#include <linux/interrupt.h>
+-#include <linux/pm_runtime.h>
+-#include <linux/intel_mid_dma.h>
+-#include <linux/module.h>
+-
+-#include "dmaengine.h"
+-
+-#define MAX_CHAN 4 /*max ch across controllers*/
+-#include "intel_mid_dma_regs.h"
+-
+-#define INTEL_MID_DMAC1_ID 0x0814
+-#define INTEL_MID_DMAC2_ID 0x0813
+-#define INTEL_MID_GP_DMAC2_ID 0x0827
+-#define INTEL_MFLD_DMAC1_ID 0x0830
+-#define LNW_PERIPHRAL_MASK_BASE 0xFFAE8008
+-#define LNW_PERIPHRAL_MASK_SIZE 0x10
+-#define LNW_PERIPHRAL_STATUS 0x0
+-#define LNW_PERIPHRAL_MASK 0x8
+-
+-struct intel_mid_dma_probe_info {
+- u8 max_chan;
+- u8 ch_base;
+- u16 block_size;
+- u32 pimr_mask;
+-};
+-
+-#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
+- ((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*/
+-/**
+- * get_ch_index - convert status to channel
+- * @status: status mask
+- * @base: dma ch base value
+- *
+- * Modify the status mask and return the channel index needing
+- * attention (or -1 if neither)
+- */
+-static int get_ch_index(int *status, unsigned int base)
+-{
+- int i;
+- for (i = 0; i < MAX_CHAN; i++) {
+- if (*status & (1 << (i + base))) {
+- *status = *status & ~(1 << (i + base));
+- pr_debug("MDMA: index %d New status %x\n", i, *status);
+- return i;
+- }
+- }
+- return -1;
+-}
+-
+-/**
+- * get_block_ts - calculates dma transaction length
+- * @len: dma transfer length
+- * @tx_width: dma transfer src width
+- * @block_size: dma controller max block size
+- *
+- * Based on src width calculate the DMA trsaction length in data items
+- * return data items or FFFF if exceeds max length for block
+- */
+-static int get_block_ts(int len, int tx_width, int block_size)
+-{
+- int byte_width = 0, block_ts = 0;
+-
+- switch (tx_width) {
+- case DMA_SLAVE_BUSWIDTH_1_BYTE:
+- byte_width = 1;
+- break;
+- case DMA_SLAVE_BUSWIDTH_2_BYTES:
+- byte_width = 2;
+- break;
+- case DMA_SLAVE_BUSWIDTH_4_BYTES:
+- default:
+- byte_width = 4;
+- break;
+- }
+-
+- block_ts = len/byte_width;
+- if (block_ts > block_size)
+- block_ts = 0xFFFF;
+- return block_ts;
+-}
+-
+-/*****************************************************************************
+-DMAC1 interrupt Functions*/
+-
+-/**
+- * dmac1_mask_periphral_intr - mask the periphral interrupt
+- * @mid: dma device for which masking is required
+- *
+- * Masks the DMA periphral interrupt
+- * this is valid for DMAC1 family controllers only
+- * This controller should have periphral mask registers already mapped
+- */
+-static void dmac1_mask_periphral_intr(struct middma_device *mid)
+-{
+- u32 pimr;
+-
+- if (mid->pimr_mask) {
+- pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
+- pimr |= mid->pimr_mask;
+- writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
+- }
+- return;
+-}
+-
+-/**
+- * dmac1_unmask_periphral_intr - unmask the periphral interrupt
+- * @midc: dma channel for which masking is required
+- *
+- * UnMasks the DMA periphral interrupt,
+- * this is valid for DMAC1 family controllers only
+- * This controller should have periphral mask registers already mapped
+- */
+-static void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
+-{
+- u32 pimr;
+- struct middma_device *mid = to_middma_device(midc->chan.device);
+-
+- if (mid->pimr_mask) {
+- pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
+- pimr &= ~mid->pimr_mask;
+- writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
+- }
+- return;
+-}
+-
+-/**
+- * enable_dma_interrupt - enable the periphral interrupt
+- * @midc: dma channel for which enable interrupt is required
+- *
+- * Enable the DMA periphral interrupt,
+- * this is valid for DMAC1 family controllers only
+- * This controller should have periphral mask registers already mapped
+- */
+-static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
+-{
+- dmac1_unmask_periphral_intr(midc);
+-
+- /*en ch interrupts*/
+- iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
+- iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
+- return;
+-}
+-
+-/**
+- * disable_dma_interrupt - disable the periphral interrupt
+- * @midc: dma channel for which disable interrupt is required
+- *
+- * Disable the DMA periphral interrupt,
+- * this is valid for DMAC1 family controllers only
+- * This controller should have periphral mask registers already mapped
+- */
+-static void disable_dma_interrupt(struct intel_mid_dma_chan *midc)
+-{
+- /*Check LPE PISR, make sure fwd is disabled*/
+- iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK);
+- iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
+- iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
+- return;
+-}
+-
+-/*****************************************************************************
+-DMA channel helper Functions*/
+-/**
+- * mid_desc_get - get a descriptor
+- * @midc: dma channel for which descriptor is required
+- *
+- * Obtain a descriptor for the channel. Returns NULL if none are free.
+- * Once the descriptor is returned it is private until put on another
+- * list or freed
+- */
+-static struct intel_mid_dma_desc *midc_desc_get(struct intel_mid_dma_chan *midc)
+-{
+- struct intel_mid_dma_desc *desc, *_desc;
+- struct intel_mid_dma_desc *ret = NULL;
+-
+- spin_lock_bh(&midc->lock);
+- list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
+- if (async_tx_test_ack(&desc->txd)) {
+- list_del(&desc->desc_node);
+- ret = desc;
+- break;
+- }
+- }
+- spin_unlock_bh(&midc->lock);
+- return ret;
+-}
+-
+-/**
+- * mid_desc_put - put a descriptor
+- * @midc: dma channel for which descriptor is required
+- * @desc: descriptor to put
+- *
+- * Return a descriptor from lwn_desc_get back to the free pool
+- */
+-static void midc_desc_put(struct intel_mid_dma_chan *midc,
+- struct intel_mid_dma_desc *desc)
+-{
+- if (desc) {
+- spin_lock_bh(&midc->lock);
+- list_add_tail(&desc->desc_node, &midc->free_list);
+- spin_unlock_bh(&midc->lock);
+- }
+-}
+-/**
+- * midc_dostart - begin a DMA transaction
+- * @midc: channel for which txn is to be started
+- * @first: first descriptor of series
+- *
+- * Load a transaction into the engine. This must be called with midc->lock
+- * held and bh disabled.
+- */
+-static void midc_dostart(struct intel_mid_dma_chan *midc,
+- struct intel_mid_dma_desc *first)
+-{
+- struct middma_device *mid = to_middma_device(midc->chan.device);
+-
+- /* channel is idle */
+- if (midc->busy && test_ch_en(midc->dma_base, midc->ch_id)) {
+- /*error*/
+- pr_err("ERR_MDMA: channel is busy in start\n");
+- /* The tasklet will hopefully advance the queue... */
+- return;
+- }
+- midc->busy = true;
+- /*write registers and en*/
+- iowrite32(first->sar, midc->ch_regs + SAR);
+- iowrite32(first->dar, midc->ch_regs + DAR);
+- iowrite32(first->lli_phys, midc->ch_regs + LLP);
+- iowrite32(first->cfg_hi, midc->ch_regs + CFG_HIGH);
+- iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
+- iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
+- iowrite32(first->ctl_hi, midc->ch_regs + CTL_HIGH);
+- pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
+- (int)first->sar, (int)first->dar, first->cfg_hi,
+- first->cfg_lo, first->ctl_hi, first->ctl_lo);
+- first->status = DMA_IN_PROGRESS;
+-
+- iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
+-}
+-
+-/**
+- * midc_descriptor_complete - process completed descriptor
+- * @midc: channel owning the descriptor
+- * @desc: the descriptor itself
+- *
+- * Process a completed descriptor and perform any callbacks upon
+- * the completion. The completion handling drops the lock during the
+- * callbacks but must be called with the lock held.
+- */
+-static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
+- struct intel_mid_dma_desc *desc)
+- __releases(&midc->lock) __acquires(&midc->lock)
+-{
+- struct dma_async_tx_descriptor *txd = &desc->txd;
+- dma_async_tx_callback callback_txd = NULL;
+- struct intel_mid_dma_lli *llitem;
+- void *param_txd = NULL;
+-
+- 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;
+- llitem->ctl_hi &= CLEAR_DONE;
+- if (desc->current_lli < desc->lli_length-1)
+- (desc->current_lli)++;
+- else
+- desc->current_lli = 0;
+- }
+- spin_unlock_bh(&midc->lock);
+- if (callback_txd) {
+- pr_debug("MDMA: TXD callback set ... calling\n");
+- callback_txd(param_txd);
+- }
+- if (midc->raw_tfr) {
+- desc->status = DMA_SUCCESS;
+- if (desc->lli != NULL) {
+- pci_pool_free(desc->lli_pool, desc->lli,
+- desc->lli_phys);
+- pci_pool_destroy(desc->lli_pool);
+- desc->lli = NULL;
+- }
+- list_move(&desc->desc_node, &midc->free_list);
+- midc->busy = false;
+- }
+- spin_lock_bh(&midc->lock);
+-
+-}
+-/**
+- * midc_scan_descriptors - check the descriptors in channel
+- * mark completed when tx is completete
+- * @mid: device
+- * @midc: channel to scan
+- *
+- * Walk the descriptor chain for the device and process any entries
+- * that are complete.
+- */
+-static void midc_scan_descriptors(struct middma_device *mid,
+- struct intel_mid_dma_chan *midc)
+-{
+- struct intel_mid_dma_desc *desc = NULL, *_desc = NULL;
+-
+- /*tx is complete*/
+- list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+- if (desc->status == DMA_IN_PROGRESS)
+- midc_descriptor_complete(midc, desc);
+- }
+- return;
+- }
+-/**
+- * midc_lli_fill_sg - Helper function to convert
+- * SG list to Linked List Items.
+- *@midc: Channel
+- *@desc: DMA descriptor
+- *@sglist: Pointer to SG list
+- *@sglen: SG list length
+- *@flags: DMA transaction flags
+- *
+- * Walk through the SG list and convert the SG list into Linked
+- * List Items (LLI).
+- */
+-static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
+- struct intel_mid_dma_desc *desc,
+- struct scatterlist *sglist,
+- unsigned int sglen,
+- unsigned int flags)
+-{
+- struct intel_mid_dma_slave *mids;
+- struct scatterlist *sg;
+- dma_addr_t lli_next, sg_phy_addr;
+- struct intel_mid_dma_lli *lli_bloc_desc;
+- union intel_mid_dma_ctl_lo ctl_lo;
+- union intel_mid_dma_ctl_hi ctl_hi;
+- int i;
+-
+- pr_debug("MDMA: Entered midc_lli_fill_sg\n");
+- mids = midc->mid_slave;
+-
+- lli_bloc_desc = desc->lli;
+- lli_next = desc->lli_phys;
+-
+- ctl_lo.ctl_lo = desc->ctl_lo;
+- ctl_hi.ctl_hi = desc->ctl_hi;
+- for_each_sg(sglist, sg, sglen, i) {
+- /*Populate CTL_LOW and LLI values*/
+- if (i != sglen - 1) {
+- lli_next = lli_next +
+- sizeof(struct intel_mid_dma_lli);
+- } else {
+- /*Check for circular list, otherwise terminate LLI to ZERO*/
+- if (flags & DMA_PREP_CIRCULAR_LIST) {
+- pr_debug("MDMA: LLI is configured in circular mode\n");
+- lli_next = desc->lli_phys;
+- } else {
+- lli_next = 0;
+- ctl_lo.ctlx.llp_dst_en = 0;
+- ctl_lo.ctlx.llp_src_en = 0;
+- }
+- }
+- /*Populate CTL_HI values*/
+- ctl_hi.ctlx.block_ts = get_block_ts(sg_dma_len(sg),
+- desc->width,
+- midc->dma->block_size);
+- /*Populate SAR and DAR values*/
+- sg_phy_addr = sg_dma_address(sg);
+- if (desc->dirn == DMA_MEM_TO_DEV) {
+- lli_bloc_desc->sar = sg_phy_addr;
+- lli_bloc_desc->dar = mids->dma_slave.dst_addr;
+- } else if (desc->dirn == DMA_DEV_TO_MEM) {
+- lli_bloc_desc->sar = mids->dma_slave.src_addr;
+- lli_bloc_desc->dar = sg_phy_addr;
+- }
+- /*Copy values into block descriptor in system memroy*/
+- lli_bloc_desc->llp = lli_next;
+- lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
+- lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
+-
+- lli_bloc_desc++;
+- }
+- /*Copy very first LLI values to descriptor*/
+- desc->ctl_lo = desc->lli->ctl_lo;
+- desc->ctl_hi = desc->lli->ctl_hi;
+- desc->sar = desc->lli->sar;
+- desc->dar = desc->lli->dar;
+-
+- return 0;
+-}
+-/*****************************************************************************
+-DMA engine callback Functions*/
+-/**
+- * intel_mid_dma_tx_submit - callback to submit DMA transaction
+- * @tx: dma engine descriptor
+- *
+- * Submit the DMA transaction for this descriptor, start if ch idle
+- */
+-static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+-{
+- struct intel_mid_dma_desc *desc = to_intel_mid_dma_desc(tx);
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(tx->chan);
+- dma_cookie_t cookie;
+-
+- spin_lock_bh(&midc->lock);
+- cookie = dma_cookie_assign(tx);
+-
+- if (list_empty(&midc->active_list))
+- list_add_tail(&desc->desc_node, &midc->active_list);
+- else
+- list_add_tail(&desc->desc_node, &midc->queue);
+-
+- midc_dostart(midc, desc);
+- spin_unlock_bh(&midc->lock);
+-
+- return cookie;
+-}
+-
+-/**
+- * intel_mid_dma_issue_pending - callback to issue pending txn
+- * @chan: chan where pending trascation needs to be checked and submitted
+- *
+- * Call for scan to issue pending descriptors
+- */
+-static void intel_mid_dma_issue_pending(struct dma_chan *chan)
+-{
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+-
+- spin_lock_bh(&midc->lock);
+- if (!list_empty(&midc->queue))
+- midc_scan_descriptors(to_middma_device(chan->device), midc);
+- spin_unlock_bh(&midc->lock);
+-}
+-
+-/**
+- * intel_mid_dma_tx_status - Return status of txn
+- * @chan: chan for where status needs to be checked
+- * @cookie: cookie for txn
+- * @txstate: DMA txn state
+- *
+- * Return status of DMA txn
+- */
+-static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
+- dma_cookie_t cookie,
+- struct dma_tx_state *txstate)
+-{
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+- enum dma_status ret;
+-
+- ret = dma_cookie_status(chan, cookie, txstate);
+- if (ret != DMA_SUCCESS) {
+- spin_lock_bh(&midc->lock);
+- midc_scan_descriptors(to_middma_device(chan->device), midc);
+- spin_unlock_bh(&midc->lock);
+-
+- ret = dma_cookie_status(chan, cookie, txstate);
+- }
+-
+- return ret;
+-}
+-
+-static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
+-{
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+- struct dma_slave_config *slave = (struct dma_slave_config *)arg;
+- struct intel_mid_dma_slave *mid_slave;
+-
+- BUG_ON(!midc);
+- BUG_ON(!slave);
+- pr_debug("MDMA: slave control called\n");
+-
+- mid_slave = to_intel_mid_dma_slave(slave);
+-
+- BUG_ON(!mid_slave);
+-
+- midc->mid_slave = mid_slave;
+- return 0;
+-}
+-/**
+- * intel_mid_dma_device_control - DMA device control
+- * @chan: chan for DMA control
+- * @cmd: control cmd
+- * @arg: cmd arg value
+- *
+- * Perform DMA control command
+- */
+-static int intel_mid_dma_device_control(struct dma_chan *chan,
+- enum dma_ctrl_cmd cmd, unsigned long arg)
+-{
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+- struct middma_device *mid = to_middma_device(chan->device);
+- struct intel_mid_dma_desc *desc, *_desc;
+- union intel_mid_dma_cfg_lo cfg_lo;
+-
+- if (cmd == DMA_SLAVE_CONFIG)
+- return dma_slave_control(chan, arg);
+-
+- if (cmd != DMA_TERMINATE_ALL)
+- return -ENXIO;
+-
+- spin_lock_bh(&midc->lock);
+- if (midc->busy == false) {
+- spin_unlock_bh(&midc->lock);
+- return 0;
+- }
+- /*Suspend and disable the channel*/
+- cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
+- cfg_lo.cfgx.ch_susp = 1;
+- iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
+- iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
+- midc->busy = false;
+- /* Disable interrupts */
+- disable_dma_interrupt(midc);
+- midc->descs_allocated = 0;
+-
+- spin_unlock_bh(&midc->lock);
+- list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+- if (desc->lli != NULL) {
+- pci_pool_free(desc->lli_pool, desc->lli,
+- desc->lli_phys);
+- pci_pool_destroy(desc->lli_pool);
+- desc->lli = NULL;
+- }
+- list_move(&desc->desc_node, &midc->free_list);
+- }
+- return 0;
+-}
+-
+-
+-/**
+- * intel_mid_dma_prep_memcpy - Prep memcpy txn
+- * @chan: chan for DMA transfer
+- * @dest: destn address
+- * @src: src address
+- * @len: DMA transfer len
+- * @flags: DMA flags
+- *
+- * Perform a DMA memcpy. Note we support slave periphral DMA transfers only
+- * The periphral txn details should be filled in slave structure properly
+- * Returns the descriptor for this txn
+- */
+-static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
+- struct dma_chan *chan, dma_addr_t dest,
+- dma_addr_t src, size_t len, unsigned long flags)
+-{
+- struct intel_mid_dma_chan *midc;
+- struct intel_mid_dma_desc *desc = NULL;
+- struct intel_mid_dma_slave *mids;
+- union intel_mid_dma_ctl_lo ctl_lo;
+- union intel_mid_dma_ctl_hi ctl_hi;
+- union intel_mid_dma_cfg_lo cfg_lo;
+- union intel_mid_dma_cfg_hi cfg_hi;
+- enum dma_slave_buswidth width;
+-
+- pr_debug("MDMA: Prep for memcpy\n");
+- BUG_ON(!chan);
+- if (!len)
+- return NULL;
+-
+- midc = to_intel_mid_dma_chan(chan);
+- BUG_ON(!midc);
+-
+- 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",
+- mids->cfg_mode, mids->dma_slave.direction,
+- mids->hs_mode, mids->dma_slave.src_addr_width);
+-
+- /*calculate CFG_LO*/
+- if (mids->hs_mode == LNW_DMA_SW_HS) {
+- cfg_lo.cfg_lo = 0;
+- cfg_lo.cfgx.hs_sel_dst = 1;
+- cfg_lo.cfgx.hs_sel_src = 1;
+- } else if (mids->hs_mode == LNW_DMA_HW_HS)
+- cfg_lo.cfg_lo = 0x00000;
+-
+- /*calculate CFG_HI*/
+- if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
+- /*SW HS only*/
+- cfg_hi.cfg_hi = 0;
+- } else {
+- cfg_hi.cfg_hi = 0;
+- if (midc->dma->pimr_mask) {
+- cfg_hi.cfgx.protctl = 0x0; /*default value*/
+- cfg_hi.cfgx.fifo_mode = 1;
+- if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
+- cfg_hi.cfgx.src_per = 0;
+- if (mids->device_instance == 0)
+- cfg_hi.cfgx.dst_per = 3;
+- if (mids->device_instance == 1)
+- cfg_hi.cfgx.dst_per = 1;
+- } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
+- if (mids->device_instance == 0)
+- cfg_hi.cfgx.src_per = 2;
+- if (mids->device_instance == 1)
+- cfg_hi.cfgx.src_per = 0;
+- cfg_hi.cfgx.dst_per = 0;
+- }
+- } else {
+- cfg_hi.cfgx.protctl = 0x1; /*default value*/
+- cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
+- midc->ch_id - midc->dma->chan_base;
+- }
+- }
+-
+- /*calculate CTL_HI*/
+- ctl_hi.ctlx.reser = 0;
+- ctl_hi.ctlx.done = 0;
+- width = mids->dma_slave.src_addr_width;
+-
+- ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
+- pr_debug("MDMA:calc len %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;
+-
+- /*
+- * Here we need some translation from "enum dma_slave_buswidth"
+- * to the format for our dma controller
+- * standard intel_mid_dmac's format
+- * 1 Byte 0b000
+- * 2 Bytes 0b001
+- * 4 Bytes 0b010
+- */
+- ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
+- ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
+-
+- if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
+- ctl_lo.ctlx.tt_fc = 0;
+- ctl_lo.ctlx.sinc = 0;
+- ctl_lo.ctlx.dinc = 0;
+- } else {
+- if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
+- ctl_lo.ctlx.sinc = 0;
+- ctl_lo.ctlx.dinc = 2;
+- ctl_lo.ctlx.tt_fc = 1;
+- } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
+- ctl_lo.ctlx.sinc = 2;
+- ctl_lo.ctlx.dinc = 0;
+- ctl_lo.ctlx.tt_fc = 2;
+- }
+- }
+-
+- pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
+- ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
+-
+- enable_dma_interrupt(midc);
+-
+- desc = midc_desc_get(midc);
+- if (desc == NULL)
+- goto err_desc_get;
+- desc->sar = src;
+- desc->dar = dest ;
+- desc->len = len;
+- desc->cfg_hi = cfg_hi.cfg_hi;
+- desc->cfg_lo = cfg_lo.cfg_lo;
+- desc->ctl_lo = ctl_lo.ctl_lo;
+- desc->ctl_hi = ctl_hi.ctl_hi;
+- desc->width = width;
+- desc->dirn = mids->dma_slave.direction;
+- desc->lli_phys = 0;
+- desc->lli = NULL;
+- desc->lli_pool = NULL;
+- return &desc->txd;
+-
+-err_desc_get:
+- pr_err("ERR_MDMA: Failed to get desc\n");
+- midc_desc_put(midc, desc);
+- return NULL;
+-}
+-/**
+- * intel_mid_dma_prep_slave_sg - Prep slave sg txn
+- * @chan: chan for DMA transfer
+- * @sgl: scatter gather list
+- * @sg_len: length of sg txn
+- * @direction: DMA transfer dirtn
+- * @flags: DMA flags
+- * @context: transfer context (ignored)
+- *
+- * Prepares LLI based periphral transfer
+- */
+-static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
+- struct dma_chan *chan, struct scatterlist *sgl,
+- unsigned int sg_len, enum dma_transfer_direction direction,
+- unsigned long flags, void *context)
+-{
+- struct intel_mid_dma_chan *midc = NULL;
+- struct intel_mid_dma_slave *mids = NULL;
+- struct intel_mid_dma_desc *desc = NULL;
+- struct dma_async_tx_descriptor *txd = NULL;
+- union intel_mid_dma_ctl_lo ctl_lo;
+-
+- pr_debug("MDMA: Prep for slave SG\n");
+-
+- if (!sg_len) {
+- pr_err("MDMA: Invalid SG length\n");
+- return NULL;
+- }
+- midc = to_intel_mid_dma_chan(chan);
+- BUG_ON(!midc);
+-
+- mids = midc->mid_slave;
+- BUG_ON(!mids);
+-
+- if (!midc->dma->pimr_mask) {
+- /* We can still handle sg list with only one item */
+- if (sg_len == 1) {
+- txd = intel_mid_dma_prep_memcpy(chan,
+- mids->dma_slave.dst_addr,
+- mids->dma_slave.src_addr,
+- sg_dma_len(sgl),
+- flags);
+- return txd;
+- } else {
+- pr_warn("MDMA: SG list is not supported by this controller\n");
+- return NULL;
+- }
+- }
+-
+- pr_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);
+- if (NULL == txd) {
+- pr_err("MDMA: Prep memcpy failed\n");
+- return NULL;
+- }
+-
+- desc = to_intel_mid_dma_desc(txd);
+- desc->dirn = direction;
+- ctl_lo.ctl_lo = desc->ctl_lo;
+- ctl_lo.ctlx.llp_dst_en = 1;
+- ctl_lo.ctlx.llp_src_en = 1;
+- desc->ctl_lo = ctl_lo.ctl_lo;
+- desc->lli_length = sg_len;
+- desc->current_lli = 0;
+- /* DMA coherent memory pool for LLI descriptors*/
+- desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
+- midc->dma->pdev,
+- (sizeof(struct intel_mid_dma_lli)*sg_len),
+- 32, 0);
+- if (NULL == desc->lli_pool) {
+- pr_err("MID_DMA:LLI pool create failed\n");
+- return NULL;
+- }
+-
+- desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
+- if (!desc->lli) {
+- pr_err("MID_DMA: LLI alloc failed\n");
+- pci_pool_destroy(desc->lli_pool);
+- return NULL;
+- }
+-
+- midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
+- if (flags & DMA_PREP_INTERRUPT) {
+- iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- midc->dma_base + MASK_BLOCK);
+- pr_debug("MDMA:Enabled Block interrupt\n");
+- }
+- return &desc->txd;
+-}
+-
+-/**
+- * intel_mid_dma_free_chan_resources - Frees dma resources
+- * @chan: chan requiring attention
+- *
+- * Frees the allocated resources on this DMA chan
+- */
+-static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
+-{
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+- struct middma_device *mid = to_middma_device(chan->device);
+- struct intel_mid_dma_desc *desc, *_desc;
+-
+- if (true == midc->busy) {
+- /*trying to free ch in use!!!!!*/
+- pr_err("ERR_MDMA: trying to free ch in use\n");
+- }
+- spin_lock_bh(&midc->lock);
+- midc->descs_allocated = 0;
+- list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
+- list_del(&desc->desc_node);
+- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
+- }
+- list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
+- list_del(&desc->desc_node);
+- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
+- }
+- list_for_each_entry_safe(desc, _desc, &midc->queue, desc_node) {
+- list_del(&desc->desc_node);
+- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
+- }
+- spin_unlock_bh(&midc->lock);
+- midc->in_use = false;
+- midc->busy = false;
+- /* Disable CH interrupts */
+- iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
+- iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
+- pm_runtime_put(&mid->pdev->dev);
+-}
+-
+-/**
+- * intel_mid_dma_alloc_chan_resources - Allocate dma resources
+- * @chan: chan requiring attention
+- *
+- * Allocates DMA resources on this chan
+- * Return the descriptors allocated
+- */
+-static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
+-{
+- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
+- struct middma_device *mid = to_middma_device(chan->device);
+- struct intel_mid_dma_desc *desc;
+- dma_addr_t phys;
+- int i = 0;
+-
+- pm_runtime_get_sync(&mid->pdev->dev);
+-
+- if (mid->state == SUSPENDED) {
+- if (dma_resume(&mid->pdev->dev)) {
+- pr_err("ERR_MDMA: resume failed");
+- return -EFAULT;
+- }
+- }
+-
+- /* ASSERT: channel is idle */
+- if (test_ch_en(mid->dma_base, midc->ch_id)) {
+- /*ch is not idle*/
+- pr_err("ERR_MDMA: ch not idle\n");
+- pm_runtime_put(&mid->pdev->dev);
+- return -EIO;
+- }
+- dma_cookie_init(chan);
+-
+- spin_lock_bh(&midc->lock);
+- while (midc->descs_allocated < DESCS_PER_CHANNEL) {
+- spin_unlock_bh(&midc->lock);
+- desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
+- if (!desc) {
+- pr_err("ERR_MDMA: desc failed\n");
+- pm_runtime_put(&mid->pdev->dev);
+- return -ENOMEM;
+- /*check*/
+- }
+- dma_async_tx_descriptor_init(&desc->txd, chan);
+- desc->txd.tx_submit = intel_mid_dma_tx_submit;
+- desc->txd.flags = DMA_CTRL_ACK;
+- desc->txd.phys = phys;
+- spin_lock_bh(&midc->lock);
+- i = ++midc->descs_allocated;
+- list_add_tail(&desc->desc_node, &midc->free_list);
+- }
+- spin_unlock_bh(&midc->lock);
+- midc->in_use = true;
+- midc->busy = false;
+- pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
+- return i;
+-}
+-
+-/**
+- * midc_handle_error - Handle DMA txn error
+- * @mid: controller where error occurred
+- * @midc: chan where error occurred
+- *
+- * Scan the descriptor for error
+- */
+-static void midc_handle_error(struct middma_device *mid,
+- struct intel_mid_dma_chan *midc)
+-{
+- midc_scan_descriptors(mid, midc);
+-}
+-
+-/**
+- * dma_tasklet - DMA interrupt tasklet
+- * @data: tasklet arg (the controller structure)
+- *
+- * Scan the controller for interrupts for completion/error
+- * Clear the interrupt and call for handling completion/error
+- */
+-static void dma_tasklet(unsigned long data)
+-{
+- struct middma_device *mid = NULL;
+- struct intel_mid_dma_chan *midc = NULL;
+- u32 status, raw_tfr, raw_block;
+- int i;
+-
+- mid = (struct middma_device *)data;
+- if (mid == NULL) {
+- pr_err("ERR_MDMA: tasklet Null param\n");
+- return;
+- }
+- pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
+- raw_tfr = ioread32(mid->dma_base + RAW_TFR);
+- raw_block = ioread32(mid->dma_base + RAW_BLOCK);
+- status = raw_tfr | raw_block;
+- status &= mid->intr_mask;
+- while (status) {
+- /*txn interrupt*/
+- i = get_ch_index(&status, mid->chan_base);
+- if (i < 0) {
+- pr_err("ERR_MDMA:Invalid ch index %x\n", i);
+- return;
+- }
+- midc = &mid->ch[i];
+- if (midc == NULL) {
+- pr_err("ERR_MDMA:Null param midc\n");
+- return;
+- }
+- pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
+- status, midc->ch_id, i);
+- midc->raw_tfr = raw_tfr;
+- midc->raw_block = raw_block;
+- spin_lock_bh(&midc->lock);
+- /*clearing this interrupts first*/
+- iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
+- if (raw_block) {
+- iowrite32((1 << midc->ch_id),
+- mid->dma_base + CLEAR_BLOCK);
+- }
+- midc_scan_descriptors(mid, midc);
+- pr_debug("MDMA:Scan of desc... complete, unmasking\n");
+- iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- mid->dma_base + MASK_TFR);
+- if (raw_block) {
+- iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- mid->dma_base + MASK_BLOCK);
+- }
+- spin_unlock_bh(&midc->lock);
+- }
+-
+- status = ioread32(mid->dma_base + RAW_ERR);
+- status &= mid->intr_mask;
+- while (status) {
+- /*err interrupt*/
+- i = get_ch_index(&status, mid->chan_base);
+- if (i < 0) {
+- pr_err("ERR_MDMA:Invalid ch index %x\n", i);
+- return;
+- }
+- midc = &mid->ch[i];
+- if (midc == NULL) {
+- pr_err("ERR_MDMA:Null param midc\n");
+- return;
+- }
+- pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
+- status, midc->ch_id, i);
+-
+- iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_ERR);
+- spin_lock_bh(&midc->lock);
+- midc_handle_error(mid, midc);
+- iowrite32(UNMASK_INTR_REG(midc->ch_id),
+- mid->dma_base + MASK_ERR);
+- spin_unlock_bh(&midc->lock);
+- }
+- pr_debug("MDMA:Exiting takslet...\n");
+- return;
+-}
+-
+-static void dma_tasklet1(unsigned long data)
+-{
+- pr_debug("MDMA:in takslet1...\n");
+- return dma_tasklet(data);
+-}
+-
+-static void dma_tasklet2(unsigned long data)
+-{
+- pr_debug("MDMA:in takslet2...\n");
+- return dma_tasklet(data);
+-}
+-
+-/**
+- * intel_mid_dma_interrupt - DMA ISR
+- * @irq: IRQ where interrupt occurred
+- * @data: ISR cllback data (the controller structure)
+- *
+- * See if this is our interrupt if so then schedule the tasklet
+- * otherwise ignore
+- */
+-static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
+-{
+- struct middma_device *mid = data;
+- u32 tfr_status, err_status;
+- int call_tasklet = 0;
+-
+- tfr_status = ioread32(mid->dma_base + RAW_TFR);
+- err_status = ioread32(mid->dma_base + RAW_ERR);
+- if (!tfr_status && !err_status)
+- return IRQ_NONE;
+-
+- /*DMA Interrupt*/
+- pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
+- pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
+- tfr_status &= mid->intr_mask;
+- if (tfr_status) {
+- /*need to disable intr*/
+- iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
+- iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
+- pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
+- call_tasklet = 1;
+- }
+- err_status &= mid->intr_mask;
+- if (err_status) {
+- iowrite32((err_status << INT_MASK_WE),
+- mid->dma_base + MASK_ERR);
+- call_tasklet = 1;
+- }
+- if (call_tasklet)
+- tasklet_schedule(&mid->tasklet);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static irqreturn_t intel_mid_dma_interrupt1(int irq, void *data)
+-{
+- return intel_mid_dma_interrupt(irq, data);
+-}
+-
+-static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
+-{
+- return intel_mid_dma_interrupt(irq, data);
+-}
+-
+-/**
+- * mid_setup_dma - Setup the DMA controller
+- * @pdev: Controller PCI device structure
+- *
+- * Initialize the DMA controller, channels, registers with DMA engine,
+- * ISR. Initialize DMA controller channels.
+- */
+-static int mid_setup_dma(struct pci_dev *pdev)
+-{
+- struct middma_device *dma = pci_get_drvdata(pdev);
+- int err, i;
+-
+- /* DMA coherent memory pool for DMA descriptor allocations */
+- dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
+- sizeof(struct intel_mid_dma_desc),
+- 32, 0);
+- if (NULL == dma->dma_pool) {
+- pr_err("ERR_MDMA:pci_pool_create failed\n");
+- err = -ENOMEM;
+- goto err_dma_pool;
+- }
+-
+- INIT_LIST_HEAD(&dma->common.channels);
+- dma->pci_id = pdev->device;
+- if (dma->pimr_mask) {
+- dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
+- LNW_PERIPHRAL_MASK_SIZE);
+- if (dma->mask_reg == NULL) {
+- pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
+- err = -ENOMEM;
+- goto err_ioremap;
+- }
+- } else
+- dma->mask_reg = NULL;
+-
+- pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
+- /*init CH structures*/
+- dma->intr_mask = 0;
+- dma->state = RUNNING;
+- for (i = 0; i < dma->max_chan; i++) {
+- struct intel_mid_dma_chan *midch = &dma->ch[i];
+-
+- midch->chan.device = &dma->common;
+- dma_cookie_init(&midch->chan);
+- midch->ch_id = dma->chan_base + i;
+- pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id);
+-
+- midch->dma_base = dma->dma_base;
+- midch->ch_regs = dma->dma_base + DMA_CH_SIZE * midch->ch_id;
+- midch->dma = dma;
+- dma->intr_mask |= 1 << (dma->chan_base + i);
+- spin_lock_init(&midch->lock);
+-
+- INIT_LIST_HEAD(&midch->active_list);
+- INIT_LIST_HEAD(&midch->queue);
+- INIT_LIST_HEAD(&midch->free_list);
+- /*mask interrupts*/
+- iowrite32(MASK_INTR_REG(midch->ch_id),
+- dma->dma_base + MASK_BLOCK);
+- iowrite32(MASK_INTR_REG(midch->ch_id),
+- dma->dma_base + MASK_SRC_TRAN);
+- iowrite32(MASK_INTR_REG(midch->ch_id),
+- dma->dma_base + MASK_DST_TRAN);
+- iowrite32(MASK_INTR_REG(midch->ch_id),
+- dma->dma_base + MASK_ERR);
+- iowrite32(MASK_INTR_REG(midch->ch_id),
+- dma->dma_base + MASK_TFR);
+-
+- disable_dma_interrupt(midch);
+- list_add_tail(&midch->chan.device_node, &dma->common.channels);
+- }
+- pr_debug("MDMA: Calc Mask as %x for this controller\n", dma->intr_mask);
+-
+- /*init dma structure*/
+- dma_cap_zero(dma->common.cap_mask);
+- dma_cap_set(DMA_MEMCPY, dma->common.cap_mask);
+- dma_cap_set(DMA_SLAVE, dma->common.cap_mask);
+- dma_cap_set(DMA_PRIVATE, dma->common.cap_mask);
+- dma->common.dev = &pdev->dev;
+-
+- dma->common.device_alloc_chan_resources =
+- intel_mid_dma_alloc_chan_resources;
+- dma->common.device_free_chan_resources =
+- intel_mid_dma_free_chan_resources;
+-
+- dma->common.device_tx_status = intel_mid_dma_tx_status;
+- dma->common.device_prep_dma_memcpy = intel_mid_dma_prep_memcpy;
+- dma->common.device_issue_pending = intel_mid_dma_issue_pending;
+- dma->common.device_prep_slave_sg = intel_mid_dma_prep_slave_sg;
+- dma->common.device_control = intel_mid_dma_device_control;
+-
+- /*enable dma cntrl*/
+- iowrite32(REG_BIT0, dma->dma_base + DMA_CFG);
+-
+- /*register irq */
+- if (dma->pimr_mask) {
+- pr_debug("MDMA:Requesting irq shared for DMAC1\n");
+- err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
+- IRQF_SHARED, "INTEL_MID_DMAC1", dma);
+- if (0 != err)
+- goto err_irq;
+- } else {
+- dma->intr_mask = 0x03;
+- pr_debug("MDMA:Requesting irq for DMAC2\n");
+- err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
+- IRQF_SHARED, "INTEL_MID_DMAC2", dma);
+- if (0 != err)
+- goto err_irq;
+- }
+- /*register device w/ engine*/
+- err = dma_async_device_register(&dma->common);
+- if (0 != err) {
+- pr_err("ERR_MDMA:device_register failed: %d\n", err);
+- goto err_engine;
+- }
+- if (dma->pimr_mask) {
+- pr_debug("setting up tasklet1 for DMAC1\n");
+- tasklet_init(&dma->tasklet, dma_tasklet1, (unsigned long)dma);
+- } else {
+- pr_debug("setting up tasklet2 for DMAC2\n");
+- tasklet_init(&dma->tasklet, dma_tasklet2, (unsigned long)dma);
+- }
+- return 0;
+-
+-err_engine:
+- free_irq(pdev->irq, dma);
+-err_irq:
+- if (dma->mask_reg)
+- iounmap(dma->mask_reg);
+-err_ioremap:
+- pci_pool_destroy(dma->dma_pool);
+-err_dma_pool:
+- pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
+- return err;
+-
+-}
+-
+-/**
+- * middma_shutdown - Shutdown the DMA controller
+- * @pdev: Controller PCI device structure
+- *
+- * Called by remove
+- * Unregister DMa controller, clear all structures and free interrupt
+- */
+-static void middma_shutdown(struct pci_dev *pdev)
+-{
+- struct middma_device *device = pci_get_drvdata(pdev);
+-
+- dma_async_device_unregister(&device->common);
+- pci_pool_destroy(device->dma_pool);
+- if (device->mask_reg)
+- iounmap(device->mask_reg);
+- if (device->dma_base)
+- iounmap(device->dma_base);
+- free_irq(pdev->irq, device);
+- return;
+-}
+-
+-/**
+- * intel_mid_dma_probe - PCI Probe
+- * @pdev: Controller PCI device structure
+- * @id: pci device id structure
+- *
+- * Initialize the PCI device, map BARs, query driver data.
+- * Call setup_dma to complete contoller and chan initilzation
+- */
+-static int intel_mid_dma_probe(struct pci_dev *pdev,
+- const struct pci_device_id *id)
+-{
+- struct middma_device *device;
+- u32 base_addr, bar_size;
+- struct intel_mid_dma_probe_info *info;
+- int err;
+-
+- pr_debug("MDMA: probe for %x\n", pdev->device);
+- info = (void *)id->driver_data;
+- pr_debug("MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
+- info->max_chan, info->ch_base,
+- info->block_size, info->pimr_mask);
+-
+- err = pci_enable_device(pdev);
+- if (err)
+- goto err_enable_device;
+-
+- err = pci_request_regions(pdev, "intel_mid_dmac");
+- if (err)
+- goto err_request_regions;
+-
+- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+- if (err)
+- goto err_set_dma_mask;
+-
+- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+- if (err)
+- goto err_set_dma_mask;
+-
+- device = kzalloc(sizeof(*device), GFP_KERNEL);
+- if (!device) {
+- pr_err("ERR_MDMA:kzalloc failed probe\n");
+- err = -ENOMEM;
+- goto err_kzalloc;
+- }
+- device->pdev = pci_dev_get(pdev);
+-
+- base_addr = pci_resource_start(pdev, 0);
+- bar_size = pci_resource_len(pdev, 0);
+- device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
+- if (!device->dma_base) {
+- pr_err("ERR_MDMA:ioremap failed\n");
+- err = -ENOMEM;
+- goto err_ioremap;
+- }
+- pci_set_drvdata(pdev, device);
+- pci_set_master(pdev);
+- device->max_chan = info->max_chan;
+- device->chan_base = info->ch_base;
+- device->block_size = info->block_size;
+- device->pimr_mask = info->pimr_mask;
+-
+- err = mid_setup_dma(pdev);
+- if (err)
+- goto err_dma;
+-
+- pm_runtime_put_noidle(&pdev->dev);
+- pm_runtime_allow(&pdev->dev);
+- return 0;
+-
+-err_dma:
+- iounmap(device->dma_base);
+-err_ioremap:
+- pci_dev_put(pdev);
+- kfree(device);
+-err_kzalloc:
+-err_set_dma_mask:
+- pci_release_regions(pdev);
+- pci_disable_device(pdev);
+-err_request_regions:
+-err_enable_device:
+- pr_err("ERR_MDMA:Probe failed %d\n", err);
+- return err;
+-}
+-
+-/**
+- * intel_mid_dma_remove - PCI remove
+- * @pdev: Controller PCI device structure
+- *
+- * Free up all resources and data
+- * Call shutdown_dma to complete contoller and chan cleanup
+- */
+-static void intel_mid_dma_remove(struct pci_dev *pdev)
+-{
+- struct middma_device *device = pci_get_drvdata(pdev);
+-
+- pm_runtime_get_noresume(&pdev->dev);
+- pm_runtime_forbid(&pdev->dev);
+- middma_shutdown(pdev);
+- pci_dev_put(pdev);
+- kfree(device);
+- pci_release_regions(pdev);
+- pci_disable_device(pdev);
+-}
+-
+-/* Power Management */
+-/*
+-* dma_suspend - PCI suspend function
+-*
+-* @pci: PCI device structure
+-* @state: PM message
+-*
+-* This function is called by OS when a power event occurs
+-*/
+-static int dma_suspend(struct device *dev)
+-{
+- struct pci_dev *pci = to_pci_dev(dev);
+- int i;
+- struct middma_device *device = pci_get_drvdata(pci);
+- pr_debug("MDMA: dma_suspend called\n");
+-
+- for (i = 0; i < device->max_chan; i++) {
+- if (device->ch[i].in_use)
+- return -EAGAIN;
+- }
+- dmac1_mask_periphral_intr(device);
+- device->state = SUSPENDED;
+- pci_save_state(pci);
+- pci_disable_device(pci);
+- pci_set_power_state(pci, PCI_D3hot);
+- return 0;
+-}
+-
+-/**
+-* dma_resume - PCI resume function
+-*
+-* @pci: PCI device structure
+-*
+-* This function is called by OS when a power event occurs
+-*/
+-int dma_resume(struct device *dev)
+-{
+- struct pci_dev *pci = to_pci_dev(dev);
+- int ret;
+- struct middma_device *device = pci_get_drvdata(pci);
+-
+- pr_debug("MDMA: dma_resume called\n");
+- pci_set_power_state(pci, PCI_D0);
+- pci_restore_state(pci);
+- ret = pci_enable_device(pci);
+- if (ret) {
+- pr_err("MDMA: device can't be enabled for %x\n", pci->device);
+- return ret;
+- }
+- device->state = RUNNING;
+- iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+- return 0;
+-}
+-
+-static int dma_runtime_suspend(struct device *dev)
+-{
+- struct pci_dev *pci_dev = to_pci_dev(dev);
+- struct middma_device *device = pci_get_drvdata(pci_dev);
+-
+- device->state = SUSPENDED;
+- return 0;
+-}
+-
+-static int dma_runtime_resume(struct device *dev)
+-{
+- struct pci_dev *pci_dev = to_pci_dev(dev);
+- struct middma_device *device = pci_get_drvdata(pci_dev);
+-
+- device->state = RUNNING;
+- iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
+- return 0;
+-}
+-
+-static int dma_runtime_idle(struct device *dev)
+-{
+- struct pci_dev *pdev = to_pci_dev(dev);
+- struct middma_device *device = pci_get_drvdata(pdev);
+- int i;
+-
+- for (i = 0; i < device->max_chan; i++) {
+- if (device->ch[i].in_use)
+- return -EAGAIN;
+- }
+-
+- return pm_schedule_suspend(dev, 0);
+-}
+-
+-/******************************************************************************
+-* PCI stuff
+-*/
+-static struct pci_device_id intel_mid_dma_ids[] = {
+- { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
+- { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
+- { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
+- { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
+- { 0, }
+-};
+-MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
+-
+-static const struct dev_pm_ops intel_mid_dma_pm = {
+- .runtime_suspend = dma_runtime_suspend,
+- .runtime_resume = dma_runtime_resume,
+- .runtime_idle = dma_runtime_idle,
+- .suspend = dma_suspend,
+- .resume = dma_resume,
+-};
+-
+-static struct pci_driver intel_mid_dma_pci_driver = {
+- .name = "Intel MID DMA",
+- .id_table = intel_mid_dma_ids,
+- .probe = intel_mid_dma_probe,
+- .remove = intel_mid_dma_remove,
+-#ifdef CONFIG_PM
+- .driver = {
+- .pm = &intel_mid_dma_pm,
+- },
+-#endif
+-};
+-
+-static int __init intel_mid_dma_init(void)
+-{
+- pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
+- INTEL_MID_DMA_DRIVER_VERSION);
+- return pci_register_driver(&intel_mid_dma_pci_driver);
+-}
+-fs_initcall(intel_mid_dma_init);
+-
+-static void __exit intel_mid_dma_exit(void)
+-{
+- pci_unregister_driver(&intel_mid_dma_pci_driver);
+-}
+-module_exit(intel_mid_dma_exit);
+-
+-MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+-MODULE_DESCRIPTION("Intel (R) MID DMAC Driver");
+-MODULE_LICENSE("GPL v2");
+-MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
+diff --git a/drivers/dma/intel_mid_dma/Makefile b/drivers/dma/intel_mid_dma/Makefile
+new file mode 100644
+index 0000000..6ec8b97
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
++intel_mid_dma-objs:= intel_qrk_dma_pci.o intel_mid_dma_pci.o
++
+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
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma_core.c
+@@ -0,0 +1,1295 @@
++/*
++ * intel_mid_dma_core.c - Intel Langwell DMA Drivers
++ *
++ * Copyright (C) 2008-14 Intel Corp
++ * Author: Vinod Koul <vinod.koul@intel.com>
++ * The driver design is based on dw_dmac driver
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *
++ */
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/module.h>
++
++#include "dmaengine.h"
++#include "intel_mid_dma_regs.h"
++
++#define MAX_CHAN 4 /*max ch across controllers*/
++
++#define INTEL_MID_DMAC1_ID 0x0814
++#define INTEL_MID_DMAC2_ID 0x0813
++#define INTEL_MID_GP_DMAC2_ID 0x0827
++#define INTEL_MFLD_DMAC1_ID 0x0830
++#define LNW_PERIPHRAL_MASK_BASE 0xFFAE8008
++#define LNW_PERIPHRAL_MASK_SIZE 0x10
++#define LNW_PERIPHRAL_STATUS 0x0
++#define LNW_PERIPHRAL_MASK 0x8
++
++#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*/
++/**
++ * get_ch_index - convert status to channel
++ * @status: status mask
++ * @base: dma ch base value
++ *
++ * Modify the status mask and return the channel index needing
++ * attention (or -1 if neither)
++ */
++static int get_ch_index(int *status, unsigned int base)
++{
++ int i;
++ for (i = 0; i < MAX_CHAN; i++) {
++ if (*status & (1 << (i + base))) {
++ *status = *status & ~(1 << (i + base));
++ pr_debug("MDMA: index %d New status %x\n", i, *status);
++ return i;
++ }
++ }
++ return -1;
++}
++
++/**
++ * get_block_ts - calculates dma transaction length
++ * @len: dma transfer length
++ * @tx_width: dma transfer src width
++ * @block_size: dma controller max block size
++ *
++ * Based on src width calculate the DMA trsaction length in data items
++ * return data items or FFFF if exceeds max length for block
++ */
++static int get_block_ts(int len, int tx_width, int block_size)
++{
++ int byte_width = 0, block_ts = 0;
++
++ switch (tx_width) {
++ case DMA_SLAVE_BUSWIDTH_1_BYTE:
++ byte_width = 1;
++ break;
++ case DMA_SLAVE_BUSWIDTH_2_BYTES:
++ byte_width = 2;
++ break;
++ case DMA_SLAVE_BUSWIDTH_4_BYTES:
++ default:
++ byte_width = 4;
++ break;
++ }
++
++ block_ts = len/byte_width;
++ if (block_ts > block_size)
++ block_ts = 0xFFFF;
++ return block_ts;
++}
++
++/*****************************************************************************
++DMAC1 interrupt Functions*/
++
++/**
++ * dmac1_mask_periphral_intr - mask the periphral interrupt
++ * @mid: dma device for which masking is required
++ *
++ * Masks the DMA periphral interrupt
++ * this is valid for DMAC1 family controllers only
++ * This controller should have periphral mask registers already mapped
++ */
++void dmac1_mask_periphral_intr(struct middma_device *mid)
++{
++ u32 pimr;
++
++ if (mid->pimr_mask) {
++ pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
++ pimr |= mid->pimr_mask;
++ writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
++ }
++ return;
++}
++
++/**
++ * dmac1_unmask_periphral_intr - unmask the periphral interrupt
++ * @midc: dma channel for which masking is required
++ *
++ * UnMasks the DMA periphral interrupt,
++ * this is valid for DMAC1 family controllers only
++ * This controller should have periphral mask registers already mapped
++ */
++void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
++{
++ u32 pimr;
++ struct middma_device *mid = to_middma_device(midc->chan.device);
++
++ if (mid->pimr_mask) {
++ pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
++ pimr &= ~mid->pimr_mask;
++ writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
++ }
++ return;
++}
++
++/**
++ * enable_dma_interrupt - enable the periphral interrupt
++ * @midc: dma channel for which enable interrupt is required
++ *
++ * Enable the DMA periphral interrupt,
++ * this is valid for DMAC1 family controllers only
++ * This controller should have periphral mask registers already mapped
++ */
++static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
++{
++ dmac1_unmask_periphral_intr(midc);
++
++ /*en ch interrupts*/
++ iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
++ iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
++ return;
++}
++
++/**
++ * disable_dma_interrupt - disable the periphral interrupt
++ * @midc: dma channel for which disable interrupt is required
++ *
++ * Disable the DMA periphral interrupt,
++ * this is valid for DMAC1 family controllers only
++ * This controller should have periphral mask registers already mapped
++ */
++static void disable_dma_interrupt(struct intel_mid_dma_chan *midc)
++{
++ /*Check LPE PISR, make sure fwd is disabled*/
++ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK);
++ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
++ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
++ return;
++}
++
++/*****************************************************************************
++DMA channel helper Functions*/
++/**
++ * mid_desc_get - get a descriptor
++ * @midc: dma channel for which descriptor is required
++ *
++ * Obtain a descriptor for the channel. Returns NULL if none are free.
++ * Once the descriptor is returned it is private until put on another
++ * list or freed
++ */
++static struct intel_mid_dma_desc *midc_desc_get(struct intel_mid_dma_chan *midc)
++{
++ struct intel_mid_dma_desc *desc, *_desc;
++ struct intel_mid_dma_desc *ret = NULL;
++
++ spin_lock_bh(&midc->lock);
++ list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
++ if (async_tx_test_ack(&desc->txd)) {
++ list_del(&desc->desc_node);
++ ret = desc;
++ break;
++ }
++ }
++ spin_unlock_bh(&midc->lock);
++ return ret;
++}
++
++/**
++ * mid_desc_put - put a descriptor
++ * @midc: dma channel for which descriptor is required
++ * @desc: descriptor to put
++ *
++ * Return a descriptor from lwn_desc_get back to the free pool
++ */
++static void midc_desc_put(struct intel_mid_dma_chan *midc,
++ struct intel_mid_dma_desc *desc)
++{
++ if (desc) {
++ spin_lock_bh(&midc->lock);
++ list_add_tail(&desc->desc_node, &midc->free_list);
++ spin_unlock_bh(&midc->lock);
++ }
++}
++/**
++ * midc_dostart - begin a DMA transaction
++ * @midc: channel for which txn is to be started
++ * @first: first descriptor of series
++ *
++ * Load a transaction into the engine. This must be called with midc->lock
++ * held and bh disabled.
++ */
++static void midc_dostart(struct intel_mid_dma_chan *midc,
++ struct intel_mid_dma_desc *first)
++{
++ struct middma_device *mid = to_middma_device(midc->chan.device);
++
++ /* channel is idle */
++ if (midc->busy && test_ch_en(midc->dma_base, midc->ch_id)) {
++ /*error*/
++ pr_err("ERR_MDMA: channel is busy in start\n");
++ /* The tasklet will hopefully advance the queue... */
++ return;
++ }
++ midc->busy = true;
++ /*write registers and en*/
++ iowrite32(first->sar, midc->ch_regs + SAR);
++ iowrite32(first->dar, midc->ch_regs + DAR);
++ iowrite32(first->lli_phys, midc->ch_regs + LLP);
++ iowrite32(first->cfg_hi, midc->ch_regs + CFG_HIGH);
++ iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
++ iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
++ iowrite32(first->ctl_hi, midc->ch_regs + CTL_HIGH);
++ pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
++ (int)first->sar, (int)first->dar, first->cfg_hi,
++ first->cfg_lo, first->ctl_hi, first->ctl_lo);
++ first->status = DMA_IN_PROGRESS;
++
++ iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
++}
++
++/**
++ * midc_descriptor_complete - process completed descriptor
++ * @midc: channel owning the descriptor
++ * @desc: the descriptor itself
++ *
++ * Process a completed descriptor and perform any callbacks upon
++ * the completion. The completion handling drops the lock during the
++ * callbacks but must be called with the lock held.
++ */
++static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
++ struct intel_mid_dma_desc *desc)
++ __releases(&midc->lock) __acquires(&midc->lock)
++{
++ struct dma_async_tx_descriptor *txd = &desc->txd;
++ dma_async_tx_callback callback_txd = NULL;
++ struct intel_mid_dma_lli *llitem;
++ void *param_txd = NULL;
++
++ 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;
++ llitem->ctl_hi &= CLEAR_DONE;
++ if (desc->current_lli < desc->lli_length-1)
++ (desc->current_lli)++;
++ else
++ desc->current_lli = 0;
++ }
++ spin_unlock_bh(&midc->lock);
++ if (callback_txd) {
++ pr_debug("MDMA: TXD callback set ... calling\n");
++ callback_txd(param_txd);
++ }
++ if (midc->raw_tfr) {
++ desc->status = DMA_SUCCESS;
++ if (desc->lli != NULL) {
++ pci_pool_free(desc->lli_pool, desc->lli,
++ desc->lli_phys);
++ pci_pool_destroy(desc->lli_pool);
++ desc->lli = NULL;
++ }
++ list_move(&desc->desc_node, &midc->free_list);
++ midc->busy = false;
++ }
++ spin_lock_bh(&midc->lock);
++
++}
++/**
++ * midc_scan_descriptors - check the descriptors in channel
++ * mark completed when tx is completete
++ * @mid: device
++ * @midc: channel to scan
++ *
++ * Walk the descriptor chain for the device and process any entries
++ * that are complete.
++ */
++static void midc_scan_descriptors(struct middma_device *mid,
++ struct intel_mid_dma_chan *midc)
++{
++ struct intel_mid_dma_desc *desc = NULL, *_desc = NULL;
++
++ /*tx is complete*/
++ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
++ if (desc->status == DMA_IN_PROGRESS)
++ midc_descriptor_complete(midc, desc);
++ }
++ return;
++ }
++/**
++ * midc_lli_fill_sg - Helper function to convert
++ * SG list to Linked List Items.
++ *@midc: Channel
++ *@desc: DMA descriptor
++ *@sglist: Pointer to SG list
++ *@sglen: SG list length
++ *@flags: DMA transaction flags
++ *
++ * Walk through the SG list and convert the SG list into Linked
++ * List Items (LLI).
++ */
++static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
++ struct intel_mid_dma_desc *desc,
++ struct scatterlist *sglist,
++ unsigned int sglen,
++ unsigned int flags)
++{
++ struct intel_mid_dma_slave *mids;
++ struct scatterlist *sg;
++ dma_addr_t lli_next, sg_phy_addr;
++ struct intel_mid_dma_lli *lli_bloc_desc;
++ union intel_mid_dma_ctl_lo ctl_lo;
++ union intel_mid_dma_ctl_hi ctl_hi;
++ int i;
++
++ pr_debug("MDMA: Entered midc_lli_fill_sg\n");
++ mids = midc->mid_slave;
++
++ lli_bloc_desc = desc->lli;
++ lli_next = desc->lli_phys;
++
++ ctl_lo.ctl_lo = desc->ctl_lo;
++ ctl_hi.ctl_hi = desc->ctl_hi;
++ for_each_sg(sglist, sg, sglen, i) {
++ /*Populate CTL_LOW and LLI values*/
++ if (i != sglen - 1) {
++ lli_next = lli_next +
++ sizeof(struct intel_mid_dma_lli);
++ } else {
++ /*Check for circular list, otherwise terminate LLI to ZERO*/
++ if (flags & DMA_PREP_CIRCULAR_LIST) {
++ pr_debug("MDMA: LLI is configured in circular mode\n");
++ lli_next = desc->lli_phys;
++ } else {
++ lli_next = 0;
++ ctl_lo.ctlx.llp_dst_en = 0;
++ ctl_lo.ctlx.llp_src_en = 0;
++ }
++ }
++ /*Populate CTL_HI values*/
++ ctl_hi.ctlx.block_ts = get_block_ts(sg_dma_len(sg),
++ desc->width,
++ midc->dma->block_size);
++ /*Populate SAR and DAR values*/
++ sg_phy_addr = sg_dma_address(sg);
++ if (desc->dirn == DMA_MEM_TO_DEV) {
++ lli_bloc_desc->sar = sg_phy_addr;
++ lli_bloc_desc->dar = mids->dma_slave.dst_addr;
++ } else if (desc->dirn == DMA_DEV_TO_MEM) {
++ lli_bloc_desc->sar = mids->dma_slave.src_addr;
++ lli_bloc_desc->dar = sg_phy_addr;
++ }
++ /*Copy values into block descriptor in system memroy*/
++ lli_bloc_desc->llp = lli_next;
++ lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
++ lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
++
++ lli_bloc_desc++;
++ }
++ /*Copy very first LLI values to descriptor*/
++ desc->ctl_lo = desc->lli->ctl_lo;
++ desc->ctl_hi = desc->lli->ctl_hi;
++ desc->sar = desc->lli->sar;
++ desc->dar = desc->lli->dar;
++
++ return 0;
++}
++/*****************************************************************************
++DMA engine callback Functions*/
++/**
++ * intel_mid_dma_tx_submit - callback to submit DMA transaction
++ * @tx: dma engine descriptor
++ *
++ * Submit the DMA transaction for this descriptor, start if ch idle
++ */
++static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
++{
++ struct intel_mid_dma_desc *desc = to_intel_mid_dma_desc(tx);
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(tx->chan);
++ dma_cookie_t cookie;
++
++ spin_lock_bh(&midc->lock);
++ cookie = dma_cookie_assign(tx);
++
++ if (list_empty(&midc->active_list))
++ list_add_tail(&desc->desc_node, &midc->active_list);
++ else
++ list_add_tail(&desc->desc_node, &midc->queue);
++
++ midc_dostart(midc, desc);
++ spin_unlock_bh(&midc->lock);
++
++ return cookie;
++}
++
++/**
++ * intel_mid_dma_issue_pending - callback to issue pending txn
++ * @chan: chan where pending trascation needs to be checked and submitted
++ *
++ * Call for scan to issue pending descriptors
++ */
++static void intel_mid_dma_issue_pending(struct dma_chan *chan)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++
++ spin_lock_bh(&midc->lock);
++ if (!list_empty(&midc->queue))
++ midc_scan_descriptors(to_middma_device(chan->device), midc);
++ spin_unlock_bh(&midc->lock);
++}
++
++/**
++ * intel_mid_dma_tx_status - Return status of txn
++ * @chan: chan for where status needs to be checked
++ * @cookie: cookie for txn
++ * @txstate: DMA txn state
++ *
++ * Return status of DMA txn
++ */
++static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
++ dma_cookie_t cookie,
++ struct dma_tx_state *txstate)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ enum dma_status ret;
++
++ ret = dma_cookie_status(chan, cookie, txstate);
++ if (ret != DMA_SUCCESS) {
++ spin_lock_bh(&midc->lock);
++ midc_scan_descriptors(to_middma_device(chan->device), midc);
++ spin_unlock_bh(&midc->lock);
++
++ ret = dma_cookie_status(chan, cookie, txstate);
++ }
++
++ return ret;
++}
++
++static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ struct dma_slave_config *slave = (struct dma_slave_config *)arg;
++ struct intel_mid_dma_slave *mid_slave;
++
++ BUG_ON(!midc);
++ BUG_ON(!slave);
++ pr_debug("MDMA: slave control called\n");
++
++ mid_slave = to_intel_mid_dma_slave(slave);
++
++ BUG_ON(!mid_slave);
++
++ midc->mid_slave = mid_slave;
++ return 0;
++}
++/**
++ * intel_mid_dma_device_control - DMA device control
++ * @chan: chan for DMA control
++ * @cmd: control cmd
++ * @arg: cmd arg value
++ *
++ * Perform DMA control command
++ */
++static int intel_mid_dma_device_control(struct dma_chan *chan,
++ enum dma_ctrl_cmd cmd, unsigned long arg)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ struct middma_device *mid = to_middma_device(chan->device);
++ struct intel_mid_dma_desc *desc, *_desc;
++ union intel_mid_dma_cfg_lo cfg_lo;
++
++ if (cmd == DMA_SLAVE_CONFIG)
++ return dma_slave_control(chan, arg);
++
++ if (cmd != DMA_TERMINATE_ALL)
++ return -ENXIO;
++
++ spin_lock_bh(&midc->lock);
++ if (midc->busy == false) {
++ spin_unlock_bh(&midc->lock);
++ return 0;
++ }
++ /*Suspend and disable the channel*/
++ cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
++ cfg_lo.cfgx.ch_susp = 1;
++ iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
++ iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
++ midc->busy = false;
++ /* Disable interrupts */
++ disable_dma_interrupt(midc);
++ midc->descs_allocated = 0;
++
++ spin_unlock_bh(&midc->lock);
++ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
++ if (desc->lli != NULL) {
++ pci_pool_free(desc->lli_pool, desc->lli,
++ desc->lli_phys);
++ pci_pool_destroy(desc->lli_pool);
++ desc->lli = NULL;
++ }
++ list_move(&desc->desc_node, &midc->free_list);
++ }
++ return 0;
++}
++
++
++/**
++ * intel_mid_dma_prep_memcpy - Prep memcpy txn
++ * @chan: chan for DMA transfer
++ * @dest: destn address
++ * @src: src address
++ * @len: DMA transfer len
++ * @flags: DMA flags
++ *
++ * Perform a DMA memcpy. Note we support slave periphral DMA transfers only
++ * The periphral txn details should be filled in slave structure properly
++ * Returns the descriptor for this txn
++ */
++static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
++ struct dma_chan *chan, dma_addr_t dest,
++ dma_addr_t src, size_t len, unsigned long flags)
++{
++ struct intel_mid_dma_chan *midc;
++ struct intel_mid_dma_desc *desc = NULL;
++ struct intel_mid_dma_slave *mids;
++ union intel_mid_dma_ctl_lo ctl_lo;
++ union intel_mid_dma_ctl_hi ctl_hi;
++ union intel_mid_dma_cfg_lo cfg_lo;
++ union intel_mid_dma_cfg_hi cfg_hi;
++ enum dma_slave_buswidth width;
++
++ pr_debug("MDMA: Prep for memcpy\n");
++ BUG_ON(!chan);
++ if (!len)
++ return NULL;
++
++ midc = to_intel_mid_dma_chan(chan);
++ BUG_ON(!midc);
++
++ 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",
++ mids->cfg_mode, mids->dma_slave.direction,
++ mids->hs_mode, mids->dma_slave.src_addr_width);
++
++ /*calculate CFG_LO*/
++ if (mids->hs_mode == LNW_DMA_SW_HS) {
++ cfg_lo.cfg_lo = 0;
++ cfg_lo.cfgx.hs_sel_dst = 1;
++ cfg_lo.cfgx.hs_sel_src = 1;
++ } else if (mids->hs_mode == LNW_DMA_HW_HS)
++ cfg_lo.cfg_lo = 0x00000;
++
++ /*calculate CFG_HI*/
++ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
++ /*SW HS only*/
++ cfg_hi.cfg_hi = 0;
++ } else {
++ cfg_hi.cfg_hi = 0;
++ if (midc->dma->pimr_mask) {
++ cfg_hi.cfgx.protctl = 0x0; /*default value*/
++ cfg_hi.cfgx.fifo_mode = 1;
++ if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
++ cfg_hi.cfgx.src_per = 0;
++ if (mids->device_instance == 0)
++ cfg_hi.cfgx.dst_per = 3;
++ if (mids->device_instance == 1)
++ cfg_hi.cfgx.dst_per = 1;
++ } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
++ if (mids->device_instance == 0)
++ cfg_hi.cfgx.src_per = 2;
++ if (mids->device_instance == 1)
++ cfg_hi.cfgx.src_per = 0;
++ cfg_hi.cfgx.dst_per = 0;
++ }
++ } else {
++ cfg_hi.cfgx.protctl = 0x1; /*default value*/
++ cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
++ midc->ch_id - midc->dma->chan_base;
++ }
++ }
++
++ /*calculate CTL_HI*/
++ ctl_hi.ctlx.reser = 0;
++ ctl_hi.ctlx.done = 0;
++ width = mids->dma_slave.src_addr_width;
++
++ ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
++ pr_debug("MDMA:calc len %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;
++
++ /*
++ * Here we need some translation from "enum dma_slave_buswidth"
++ * to the format for our dma controller
++ * standard intel_mid_dmac's format
++ * 1 Byte 0b000
++ * 2 Bytes 0b001
++ * 4 Bytes 0b010
++ */
++ ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
++ ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
++
++ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
++ ctl_lo.ctlx.tt_fc = 0;
++ ctl_lo.ctlx.sinc = 0;
++ ctl_lo.ctlx.dinc = 0;
++ } else {
++ if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
++ ctl_lo.ctlx.sinc = 0;
++ ctl_lo.ctlx.dinc = 2;
++ ctl_lo.ctlx.tt_fc = 1;
++ } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
++ ctl_lo.ctlx.sinc = 2;
++ ctl_lo.ctlx.dinc = 0;
++ ctl_lo.ctlx.tt_fc = 2;
++ }
++ }
++
++ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
++ ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
++
++ enable_dma_interrupt(midc);
++
++ desc = midc_desc_get(midc);
++ if (desc == NULL)
++ goto err_desc_get;
++ desc->sar = src;
++ desc->dar = dest ;
++ desc->len = len;
++ desc->cfg_hi = cfg_hi.cfg_hi;
++ desc->cfg_lo = cfg_lo.cfg_lo;
++ desc->ctl_lo = ctl_lo.ctl_lo;
++ desc->ctl_hi = ctl_hi.ctl_hi;
++ desc->width = width;
++ desc->dirn = mids->dma_slave.direction;
++ desc->lli_phys = 0;
++ desc->lli = NULL;
++ desc->lli_pool = NULL;
++ return &desc->txd;
++
++err_desc_get:
++ pr_err("ERR_MDMA: Failed to get desc\n");
++ midc_desc_put(midc, desc);
++ return NULL;
++}
++/**
++ * intel_mid_dma_prep_slave_sg - Prep slave sg txn
++ * @chan: chan for DMA transfer
++ * @sgl: scatter gather list
++ * @sg_len: length of sg txn
++ * @direction: DMA transfer dirtn
++ * @flags: DMA flags
++ * @context: transfer context (ignored)
++ *
++ * Prepares LLI based periphral transfer
++ */
++static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
++ struct dma_chan *chan, struct scatterlist *sgl,
++ unsigned int sg_len, enum dma_transfer_direction direction,
++ unsigned long flags, void *context)
++{
++ struct intel_mid_dma_chan *midc = NULL;
++ struct intel_mid_dma_slave *mids = NULL;
++ struct intel_mid_dma_desc *desc = NULL;
++ struct dma_async_tx_descriptor *txd = NULL;
++ union intel_mid_dma_ctl_lo ctl_lo;
++
++ pr_debug("MDMA: Prep for slave SG\n");
++
++ if (!sg_len) {
++ pr_err("MDMA: Invalid SG length\n");
++ return NULL;
++ }
++ midc = to_intel_mid_dma_chan(chan);
++ BUG_ON(!midc);
++
++ mids = midc->mid_slave;
++ BUG_ON(!mids);
++
++ if (!midc->dma->pimr_mask) {
++ /* We can still handle sg list with only one item */
++ if (sg_len == 1) {
++ txd = intel_mid_dma_prep_memcpy(chan,
++ mids->dma_slave.dst_addr,
++ mids->dma_slave.src_addr,
++ sg_dma_len(sgl),
++ flags);
++ return txd;
++ } else {
++ pr_warn("MDMA: SG list is not supported by this controller\n");
++ return NULL;
++ }
++ }
++
++ pr_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);
++ if (NULL == txd) {
++ pr_err("MDMA: Prep memcpy failed\n");
++ return NULL;
++ }
++
++ desc = to_intel_mid_dma_desc(txd);
++ desc->dirn = direction;
++ ctl_lo.ctl_lo = desc->ctl_lo;
++ ctl_lo.ctlx.llp_dst_en = 1;
++ ctl_lo.ctlx.llp_src_en = 1;
++ desc->ctl_lo = ctl_lo.ctl_lo;
++ desc->lli_length = sg_len;
++ desc->current_lli = 0;
++ /* DMA coherent memory pool for LLI descriptors*/
++ desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
++ midc->dma->pdev,
++ (sizeof(struct intel_mid_dma_lli)*sg_len),
++ 32, 0);
++ if (NULL == desc->lli_pool) {
++ pr_err("MID_DMA:LLI pool create failed\n");
++ return NULL;
++ }
++
++ desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
++ if (!desc->lli) {
++ pr_err("MID_DMA: LLI alloc failed\n");
++ pci_pool_destroy(desc->lli_pool);
++ return NULL;
++ }
++
++ midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
++ if (flags & DMA_PREP_INTERRUPT) {
++ iowrite32(UNMASK_INTR_REG(midc->ch_id),
++ midc->dma_base + MASK_BLOCK);
++ pr_debug("MDMA:Enabled Block interrupt\n");
++ }
++ return &desc->txd;
++}
++
++/**
++ * intel_mid_dma_free_chan_resources - Frees dma resources
++ * @chan: chan requiring attention
++ *
++ * Frees the allocated resources on this DMA chan
++ */
++static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ struct middma_device *mid = to_middma_device(chan->device);
++ struct intel_mid_dma_desc *desc, *_desc;
++
++ if (true == midc->busy) {
++ /*trying to free ch in use!!!!!*/
++ pr_err("ERR_MDMA: trying to free ch in use\n");
++ }
++ spin_lock_bh(&midc->lock);
++ midc->descs_allocated = 0;
++ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
++ list_del(&desc->desc_node);
++ pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
++ }
++ list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
++ list_del(&desc->desc_node);
++ pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
++ }
++ list_for_each_entry_safe(desc, _desc, &midc->queue, desc_node) {
++ list_del(&desc->desc_node);
++ pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
++ }
++ spin_unlock_bh(&midc->lock);
++ midc->in_use = false;
++ midc->busy = false;
++ /* Disable CH interrupts */
++ iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
++ iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
++ pm_runtime_put(&mid->pdev->dev);
++}
++
++/**
++ * intel_mid_dma_alloc_chan_resources - Allocate dma resources
++ * @chan: chan requiring attention
++ *
++ * Allocates DMA resources on this chan
++ * Return the descriptors allocated
++ */
++static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
++{
++ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
++ struct middma_device *mid = to_middma_device(chan->device);
++ struct intel_mid_dma_desc *desc;
++ dma_addr_t phys;
++ int i = 0;
++
++ pm_runtime_get_sync(&mid->pdev->dev);
++
++ if (mid->state == SUSPENDED) {
++ if (dma_resume(&mid->pdev->dev)) {
++ pr_err("ERR_MDMA: resume failed");
++ return -EFAULT;
++ }
++ }
++
++ /* ASSERT: channel is idle */
++ if (test_ch_en(mid->dma_base, midc->ch_id)) {
++ /*ch is not idle*/
++ pr_err("ERR_MDMA: ch not idle\n");
++ pm_runtime_put(&mid->pdev->dev);
++ return -EIO;
++ }
++ dma_cookie_init(chan);
++
++ spin_lock_bh(&midc->lock);
++ while (midc->descs_allocated < DESCS_PER_CHANNEL) {
++ spin_unlock_bh(&midc->lock);
++ desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
++ if (!desc) {
++ pr_err("ERR_MDMA: desc failed\n");
++ pm_runtime_put(&mid->pdev->dev);
++ return -ENOMEM;
++ /*check*/
++ }
++ dma_async_tx_descriptor_init(&desc->txd, chan);
++ desc->txd.tx_submit = intel_mid_dma_tx_submit;
++ desc->txd.flags = DMA_CTRL_ACK;
++ desc->txd.phys = phys;
++ spin_lock_bh(&midc->lock);
++ i = ++midc->descs_allocated;
++ list_add_tail(&desc->desc_node, &midc->free_list);
++ }
++ spin_unlock_bh(&midc->lock);
++ midc->in_use = true;
++ midc->busy = false;
++ pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
++ return i;
++}
++
++/**
++ * midc_handle_error - Handle DMA txn error
++ * @mid: controller where error occurred
++ * @midc: chan where error occurred
++ *
++ * Scan the descriptor for error
++ */
++static void midc_handle_error(struct middma_device *mid,
++ struct intel_mid_dma_chan *midc)
++{
++ midc_scan_descriptors(mid, midc);
++}
++
++/**
++ * dma_tasklet - DMA interrupt tasklet
++ * @data: tasklet arg (the controller structure)
++ *
++ * Scan the controller for interrupts for completion/error
++ * Clear the interrupt and call for handling completion/error
++ */
++static void dma_tasklet(unsigned long data)
++{
++ struct middma_device *mid = NULL;
++ struct intel_mid_dma_chan *midc = NULL;
++ u32 status, raw_tfr, raw_block;
++ int i;
++
++ mid = (struct middma_device *)data;
++ if (mid == NULL) {
++ pr_err("ERR_MDMA: tasklet Null param\n");
++ return;
++ }
++ pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
++ raw_tfr = ioread32(mid->dma_base + RAW_TFR);
++ raw_block = ioread32(mid->dma_base + RAW_BLOCK);
++ status = raw_tfr | raw_block;
++ status &= mid->intr_mask;
++ while (status) {
++ /*txn interrupt*/
++ i = get_ch_index(&status, mid->chan_base);
++ if (i < 0) {
++ pr_err("ERR_MDMA:Invalid ch index %x\n", i);
++ return;
++ }
++ midc = &mid->ch[i];
++ if (midc == NULL) {
++ pr_err("ERR_MDMA:Null param midc\n");
++ return;
++ }
++ pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
++ status, midc->ch_id, i);
++ midc->raw_tfr = raw_tfr;
++ midc->raw_block = raw_block;
++ spin_lock_bh(&midc->lock);
++ /*clearing this interrupts first*/
++ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
++ if (raw_block) {
++ iowrite32((1 << midc->ch_id),
++ mid->dma_base + CLEAR_BLOCK);
++ }
++ midc_scan_descriptors(mid, midc);
++ pr_debug("MDMA:Scan of desc... complete, unmasking\n");
++ iowrite32(UNMASK_INTR_REG(midc->ch_id),
++ mid->dma_base + MASK_TFR);
++ if (raw_block) {
++ iowrite32(UNMASK_INTR_REG(midc->ch_id),
++ mid->dma_base + MASK_BLOCK);
++ }
++ spin_unlock_bh(&midc->lock);
++ }
++
++ status = ioread32(mid->dma_base + RAW_ERR);
++ status &= mid->intr_mask;
++ while (status) {
++ /*err interrupt*/
++ i = get_ch_index(&status, mid->chan_base);
++ if (i < 0) {
++ pr_err("ERR_MDMA:Invalid ch index %x\n", i);
++ return;
++ }
++ midc = &mid->ch[i];
++ if (midc == NULL) {
++ pr_err("ERR_MDMA:Null param midc\n");
++ return;
++ }
++ pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
++ status, midc->ch_id, i);
++
++ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_ERR);
++ spin_lock_bh(&midc->lock);
++ midc_handle_error(mid, midc);
++ iowrite32(UNMASK_INTR_REG(midc->ch_id),
++ mid->dma_base + MASK_ERR);
++ spin_unlock_bh(&midc->lock);
++ }
++ pr_debug("MDMA:Exiting takslet...\n");
++ return;
++}
++
++static void dma_tasklet1(unsigned long data)
++{
++ pr_debug("MDMA:in takslet1...\n");
++ return dma_tasklet(data);
++}
++
++static void dma_tasklet2(unsigned long data)
++{
++ pr_debug("MDMA:in takslet2...\n");
++ return dma_tasklet(data);
++}
++
++/**
++ * intel_mid_dma_interrupt - DMA ISR
++ * @irq: IRQ where interrupt occurred
++ * @data: ISR cllback data (the controller structure)
++ *
++ * See if this is our interrupt if so then schedule the tasklet
++ * otherwise ignore
++ */
++irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
++{
++ struct middma_device *mid = data;
++ u32 tfr_status, err_status;
++ int call_tasklet = 0;
++
++ tfr_status = ioread32(mid->dma_base + RAW_TFR);
++ err_status = ioread32(mid->dma_base + RAW_ERR);
++ if (!tfr_status && !err_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);
++
++#endif
++ tfr_status &= mid->intr_mask;
++ if (tfr_status) {
++ /*need to disable intr*/
++ iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
++ iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
++ pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
++ call_tasklet = 1;
++ }
++ err_status &= mid->intr_mask;
++ if (err_status) {
++ iowrite32((err_status << INT_MASK_WE),
++ mid->dma_base + MASK_ERR);
++ call_tasklet = 1;
++ }
++ if (call_tasklet)
++ tasklet_schedule(&mid->tasklet);
++
++ return IRQ_HANDLED;
++}
++EXPORT_SYMBOL(intel_mid_dma_interrupt);
++
++static irqreturn_t intel_mid_dma_interrupt1(int irq, void *data)
++{
++ return intel_mid_dma_interrupt(irq, data);
++}
++
++static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
++{
++ return intel_mid_dma_interrupt(irq, data);
++}
++
++/**
++ * mid_setup_dma - Setup the DMA controller
++ * @pdev: Controller PCI device structure
++ *
++ * Initialize the DMA controller, channels, registers with DMA engine,
++ * ISR. Initialize DMA controller channels.
++ */
++int mid_setup_dma(struct pci_dev *pdev, struct middma_device *dma)
++{
++ int err, i;
++
++ /* DMA coherent memory pool for DMA descriptor allocations */
++ dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
++ sizeof(struct intel_mid_dma_desc),
++ 32, 0);
++ if (NULL == dma->dma_pool) {
++ pr_err("ERR_MDMA:pci_pool_create failed\n");
++ err = -ENOMEM;
++ goto err_dma_pool;
++ }
++
++ INIT_LIST_HEAD(&dma->common.channels);
++ dma->pci_id = pdev->device;
++ if (dma->pimr_mask) {
++ dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
++ LNW_PERIPHRAL_MASK_SIZE);
++ if (dma->mask_reg == NULL) {
++ pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
++ err = -ENOMEM;
++ goto err_ioremap;
++ }
++ } else
++ dma->mask_reg = NULL;
++
++ pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
++ /*init CH structures*/
++ dma->intr_mask = 0;
++ dma->state = RUNNING;
++ for (i = 0; i < dma->max_chan; i++) {
++ struct intel_mid_dma_chan *midch = &dma->ch[i];
++
++ midch->chan.device = &dma->common;
++ dma_cookie_init(&midch->chan);
++ midch->ch_id = dma->chan_base + i;
++ pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id);
++
++ midch->dma_base = dma->dma_base;
++ midch->ch_regs = dma->dma_base + DMA_CH_SIZE * midch->ch_id;
++ midch->dma = dma;
++ dma->intr_mask |= 1 << (dma->chan_base + i);
++ spin_lock_init(&midch->lock);
++
++ INIT_LIST_HEAD(&midch->active_list);
++ INIT_LIST_HEAD(&midch->queue);
++ INIT_LIST_HEAD(&midch->free_list);
++ /*mask interrupts*/
++ iowrite32(MASK_INTR_REG(midch->ch_id),
++ dma->dma_base + MASK_BLOCK);
++ iowrite32(MASK_INTR_REG(midch->ch_id),
++ dma->dma_base + MASK_SRC_TRAN);
++ iowrite32(MASK_INTR_REG(midch->ch_id),
++ dma->dma_base + MASK_DST_TRAN);
++ iowrite32(MASK_INTR_REG(midch->ch_id),
++ dma->dma_base + MASK_ERR);
++ iowrite32(MASK_INTR_REG(midch->ch_id),
++ dma->dma_base + MASK_TFR);
++
++ disable_dma_interrupt(midch);
++ list_add_tail(&midch->chan.device_node, &dma->common.channels);
++ }
++ pr_debug("MDMA: Calc Mask as %x for this controller\n", dma->intr_mask);
++
++ /*init dma structure*/
++ dma_cap_zero(dma->common.cap_mask);
++ dma_cap_set(DMA_MEMCPY, dma->common.cap_mask);
++ dma_cap_set(DMA_SLAVE, dma->common.cap_mask);
++ dma_cap_set(DMA_PRIVATE, dma->common.cap_mask);
++ dma->common.dev = &pdev->dev;
++
++ dma->common.device_alloc_chan_resources =
++ intel_mid_dma_alloc_chan_resources;
++ dma->common.device_free_chan_resources =
++ intel_mid_dma_free_chan_resources;
++
++ dma->common.device_tx_status = intel_mid_dma_tx_status;
++ dma->common.device_prep_dma_memcpy = intel_mid_dma_prep_memcpy;
++ dma->common.device_issue_pending = intel_mid_dma_issue_pending;
++ dma->common.device_prep_slave_sg = intel_mid_dma_prep_slave_sg;
++ dma->common.device_control = intel_mid_dma_device_control;
++
++ /*enable dma cntrl*/
++ iowrite32(REG_BIT0, dma->dma_base + DMA_CFG);
++
++ /*register irq */
++ if (dma->pimr_mask) {
++ pr_debug("MDMA:Requesting irq shared for DMAC1\n");
++ err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
++ IRQF_SHARED, "INTEL_MID_DMAC1", dma);
++ if (0 != err)
++ goto err_irq;
++ } else {
++ dma->intr_mask = 0x03;
++ pr_debug("MDMA:Requesting irq for DMAC2\n");
++ err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
++ IRQF_SHARED, "INTEL_MID_DMAC2", dma);
++ if (0 != err)
++ goto err_irq;
++ }
++ /*register device w/ engine*/
++ err = dma_async_device_register(&dma->common);
++ if (0 != err) {
++ pr_err("ERR_MDMA:device_register failed: %d\n", err);
++ goto err_engine;
++ }
++ if (dma->pimr_mask) {
++ pr_debug("setting up tasklet1 for DMAC1\n");
++ tasklet_init(&dma->tasklet, dma_tasklet1, (unsigned long)dma);
++ } else {
++ pr_debug("setting up tasklet2 for DMAC2\n");
++ tasklet_init(&dma->tasklet, dma_tasklet2, (unsigned long)dma);
++ }
++ return 0;
++
++err_engine:
++ free_irq(pdev->irq, dma);
++err_irq:
++ if (dma->mask_reg)
++ iounmap(dma->mask_reg);
++err_ioremap:
++ pci_pool_destroy(dma->dma_pool);
++err_dma_pool:
++ pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
++ return err;
++
++}
++/**
++ * middma_shutdown - Shutdown the DMA controller
++ * @pdev: Controller PCI device structure
++ *
++ * Called by remove
++ * Unregister DMa controller, clear all structures and free interrupt
++ */
++void middma_shutdown(struct pci_dev *pdev, struct middma_device *device)
++{
++ dma_async_device_unregister(&device->common);
++ pci_pool_destroy(device->dma_pool);
++ if (device->mask_reg)
++ iounmap(device->mask_reg);
++ if (device->dma_base)
++ iounmap(device->dma_base);
++ free_irq(pdev->irq, device);
++ return;
++}
++
++/* Power Management */
++/*
++* dma_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++static int dma_suspend(struct device *dev)
++{
++ struct pci_dev *pci = to_pci_dev(dev);
++ int i;
++ struct middma_device *device = pci_get_drvdata(pci);
++ pr_debug("MDMA: dma_suspend called\n");
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++#if 0
++ dmac1_mask_periphral_intr(device);
++#endif
++ device->state = SUSPENDED;
++ pci_save_state(pci);
++ pci_disable_device(pci);
++ pci_set_power_state(pci, PCI_D3hot);
++ return 0;
++}
++
++/**
++* dma_resume - PCI resume function
++*
++* @pci: PCI device structure
++*
++* This function is called by OS when a power event occurs
++*/
++int middma_resume(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++
++static int dma_runtime_suspend(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = SUSPENDED;
++ return 0;
++}
++
++static int dma_runtime_resume(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++
++static int dma_runtime_idle(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++
++ return pm_schedule_suspend(dev, 0);
++}
++
+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
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma_pci.c
+@@ -0,0 +1,290 @@
++/*
++ * intel_mid_dma.c - Intel Langwell DMA Drivers
++ *
++ * Copyright (C) 2008-12 Intel Corp
++ * Author: Vinod Koul <vinod.koul@intel.com>
++ * The driver design is based on dw_dmac driver
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *
++ */
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_dma.h>
++#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) \
++ ((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), \
++ })
++
++/**
++ * intel_mid_dma_probe - PCI Probe
++ * @pdev: Controller PCI device structure
++ * @id: pci device id structure
++ *
++ * Initialize the PCI device, map BARs, query driver data.
++ * Call setup_dma to complete contoller and chan initilzation
++ */
++static int intel_mid_dma_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct middma_device *device;
++ u32 base_addr, bar_size;
++ struct intel_mid_dma_probe_info *info;
++ int err;
++
++ pr_debug("MDMA: probe for %x\n", pdev->device);
++ info = (void *)id->driver_data;
++ pr_debug("MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
++ info->max_chan, info->ch_base,
++ info->block_size, info->pimr_mask);
++
++ err = pci_enable_device(pdev);
++ if (err)
++ goto err_enable_device;
++
++ err = pci_request_regions(pdev, "intel_mid_dmac");
++ if (err)
++ goto err_request_regions;
++
++ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
++ if (err)
++ goto err_set_dma_mask;
++
++ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
++ if (err)
++ goto err_set_dma_mask;
++
++ device = kzalloc(sizeof(*device), GFP_KERNEL);
++ if (!device) {
++ pr_err("ERR_MDMA:kzalloc failed probe\n");
++ err = -ENOMEM;
++ goto err_kzalloc;
++ }
++ device->pdev = pci_dev_get(pdev);
++
++ base_addr = pci_resource_start(pdev, 0);
++ bar_size = pci_resource_len(pdev, 0);
++ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
++ if (!device->dma_base) {
++ pr_err("ERR_MDMA:ioremap failed\n");
++ err = -ENOMEM;
++ goto err_ioremap;
++ }
++ pci_set_drvdata(pdev, device);
++ pci_set_master(pdev);
++ device->max_chan = info->max_chan;
++ device->chan_base = info->ch_base;
++ device->block_size = info->block_size;
++ device->pimr_mask = info->pimr_mask;
++
++ err = mid_setup_dma(pdev, device);
++ if (err)
++ goto err_dma;
++
++ pm_runtime_put_noidle(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++ return 0;
++
++err_dma:
++ iounmap(device->dma_base);
++err_ioremap:
++ pci_dev_put(pdev);
++ kfree(device);
++err_kzalloc:
++err_set_dma_mask:
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++err_request_regions:
++err_enable_device:
++ pr_err("ERR_MDMA:Probe failed %d\n", err);
++ return err;
++}
++
++/**
++ * intel_mid_dma_remove - PCI remove
++ * @pdev: Controller PCI device structure
++ *
++ * Free up all resources and data
++ * Call shutdown_dma to complete contoller and chan cleanup
++ */
++static void intel_mid_dma_remove(struct pci_dev *pdev)
++{
++ struct middma_device *device = pci_get_drvdata(pdev);
++
++ pm_runtime_get_noresume(&pdev->dev);
++ pm_runtime_forbid(&pdev->dev);
++#if 0
++ middma_shutdown(pdev, device);
++#endif
++ pci_dev_put(pdev);
++ kfree(device);
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++}
++
++/* Power Management */
++/*
++* dma_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++static int dma_suspend(struct device *dev)
++{
++ struct pci_dev *pci = to_pci_dev(dev);
++ int i;
++ struct middma_device *device = pci_get_drvdata(pci);
++ pr_debug("MDMA: dma_suspend called\n");
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++#if 0
++ dmac1_mask_periphral_intr(device);
++#endif
++ device->state = SUSPENDED;
++ pci_save_state(pci);
++ pci_disable_device(pci);
++ pci_set_power_state(pci, PCI_D3hot);
++ return 0;
++}
++
++/**
++* dma_resume - PCI resume function
++*
++* @pci: PCI device structure
++*
++* This function is called by OS when a power event occurs
++*/
++int dma_resume(struct device *dev)
++{
++ struct pci_dev *pci = to_pci_dev(dev);
++ int ret;
++
++ pr_debug("MDMA: dma_resume called\n");
++ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ ret = pci_enable_device(pci);
++ if (ret) {
++ pr_err("MDMA: device can't be enabled for %x\n", pci->device);
++ return ret;
++ }
++
++ return middma_resume(dev);
++}
++
++static int dma_runtime_suspend(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = SUSPENDED;
++ return 0;
++}
++
++static int dma_runtime_resume(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++
++static int dma_runtime_idle(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++
++ return pm_schedule_suspend(dev, 0);
++}
++
++/******************************************************************************
++* PCI stuff
++*/
++static struct pci_device_id intel_mid_dma_ids[] = {
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
++ { 0, }
++};
++MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
++
++static const struct dev_pm_ops intel_mid_dma_pm = {
++ .runtime_suspend = dma_runtime_suspend,
++ .runtime_resume = dma_runtime_resume,
++ .runtime_idle = dma_runtime_idle,
++ .suspend = dma_suspend,
++ .resume = dma_resume,
++};
++
++static struct pci_driver intel_mid_dma_pci_driver = {
++ .name = "Intel MID DMA",
++ .id_table = intel_mid_dma_ids,
++ .probe = intel_mid_dma_probe,
++ .remove = intel_mid_dma_remove,
++#ifdef CONFIG_PM
++ .driver = {
++ .pm = &intel_mid_dma_pm,
++ },
++#endif
++};
++
++static int __init intel_mid_dma_init(void)
++{
++ pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
++ INTEL_MID_DMA_DRIVER_VERSION);
++ return pci_register_driver(&intel_mid_dma_pci_driver);
++}
++fs_initcall(intel_mid_dma_init);
++
++static void __exit intel_mid_dma_exit(void)
++{
++ pci_unregister_driver(&intel_mid_dma_pci_driver);
++}
++module_exit(intel_mid_dma_exit);
++
++MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
++MODULE_DESCRIPTION("Intel (R) MID DMAC Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
+diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
+index 17b4219..4b2ba69 100644
+--- a/drivers/dma/intel_mid_dma_regs.h
++++ b/drivers/dma/intel_mid_dma_regs.h
+@@ -27,6 +27,7 @@
+
+ #include <linux/dmaengine.h>
+ #include <linux/dmapool.h>
++#include <linux/intel_mid_dma.h>
+ #include <linux/pci_ids.h>
+
+ #define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
+@@ -158,115 +159,17 @@ union intel_mid_dma_cfg_hi {
+ };
+
+
+-/**
+- * struct intel_mid_dma_chan - internal mid representation of a DMA channel
+- * @chan: dma_chan strcture represetation for mid chan
+- * @ch_regs: MMIO register space pointer to channel register
+- * @dma_base: MMIO register space DMA engine base pointer
+- * @ch_id: DMA channel id
+- * @lock: channel spinlock
+- * @active_list: current active descriptors
+- * @queue: current queued up descriptors
+- * @free_list: current free descriptors
+- * @slave: dma slave structure
+- * @descs_allocated: total number of descriptors allocated
+- * @dma: dma device structure pointer
+- * @busy: bool representing if ch is busy (active txn) or not
+- * @in_use: bool representing if ch is in use or not
+- * @raw_tfr: raw trf interrupt received
+- * @raw_block: raw block interrupt received
+- */
+-struct intel_mid_dma_chan {
+- struct dma_chan chan;
+- void __iomem *ch_regs;
+- void __iomem *dma_base;
+- int ch_id;
+- spinlock_t lock;
+- struct list_head active_list;
+- struct list_head queue;
+- struct list_head free_list;
+- unsigned int descs_allocated;
+- struct middma_device *dma;
+- bool busy;
+- bool in_use;
+- u32 raw_tfr;
+- u32 raw_block;
+- struct intel_mid_dma_slave *mid_slave;
+-};
+-
+ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
+ struct dma_chan *chan)
+ {
+ return container_of(chan, struct intel_mid_dma_chan, chan);
+ }
+
+-enum intel_mid_dma_state {
+- RUNNING = 0,
+- SUSPENDED,
+-};
+-/**
+- * struct middma_device - internal representation of a DMA device
+- * @pdev: PCI device
+- * @dma_base: MMIO register space pointer of DMA
+- * @dma_pool: for allocating DMA descriptors
+- * @common: embedded struct dma_device
+- * @tasklet: dma tasklet for processing interrupts
+- * @ch: per channel data
+- * @pci_id: DMA device PCI ID
+- * @intr_mask: Interrupt mask to be used
+- * @mask_reg: MMIO register for periphral mask
+- * @chan_base: Base ch index (read from driver data)
+- * @max_chan: max number of chs supported (from drv_data)
+- * @block_size: Block size of DMA transfer supported (from drv_data)
+- * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
+- * @state: dma PM device state
+- */
+-struct middma_device {
+- struct pci_dev *pdev;
+- void __iomem *dma_base;
+- struct pci_pool *dma_pool;
+- struct dma_device common;
+- struct tasklet_struct tasklet;
+- struct intel_mid_dma_chan ch[MAX_CHAN];
+- unsigned int pci_id;
+- unsigned int intr_mask;
+- void __iomem *mask_reg;
+- int chan_base;
+- int max_chan;
+- int block_size;
+- unsigned int pimr_mask;
+- enum intel_mid_dma_state state;
+-};
+-
+ static inline struct middma_device *to_middma_device(struct dma_device *common)
+ {
+ return container_of(common, struct middma_device, common);
+ }
+
+-struct intel_mid_dma_desc {
+- void __iomem *block; /*ch ptr*/
+- struct list_head desc_node;
+- struct dma_async_tx_descriptor txd;
+- size_t len;
+- dma_addr_t sar;
+- dma_addr_t dar;
+- u32 cfg_hi;
+- u32 cfg_lo;
+- u32 ctl_lo;
+- u32 ctl_hi;
+- struct pci_pool *lli_pool;
+- struct intel_mid_dma_lli *lli;
+- dma_addr_t lli_phys;
+- unsigned int lli_length;
+- unsigned int current_lli;
+- dma_addr_t next;
+- enum dma_transfer_direction dirn;
+- enum dma_status status;
+- enum dma_slave_buswidth width; /*width of DMA txn*/
+- enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
+-
+-};
+-
+ 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
+ }
+
+
++int mid_setup_dma(struct pci_dev *pdev, struct middma_device *dma);
++#if 0
++void middma_shutdown(struct pci_dev *pdev, struct middma_device *device);
++void dmac1_mask_periphral_intr(struct middma_device *mid);
++void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc);
++#endif
++int middma_resume(struct device *dev);
++
+ int dma_resume(struct device *dev);
+
+ #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
+--- /dev/null
++++ b/drivers/dma/intel_qrk_dma_pci.c
+@@ -0,0 +1,155 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++/*
++ * intel_quark_dma_pci.c
++ *
++ * Author: Bryan O'Donoghue <bryan.odonoghue@intel.com>
++ * This is an entry point for Intel Quark based DMAC on Quark's UART
++ * specifically we don't have a dedicated PCI function, instead we have DMAC
++ * regs hung off of a PCI BAR. This entry/exit allows re-use of the core
++ * DMA API for MID devices manipulated to suit our BAR setup
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/module.h>
++
++//#include "intel_mid_dma_core.h"
++#include "intel_mid_dma_regs.h"
++
++/**
++ * intel_mid_dma_probe - PCI Probe
++ * @pdev: Controller PCI device structure
++ * @id: pci device id structure
++ *
++ * Initialize the PCI device, map BARs, query driver data.
++ * Call mid_setup_dma to complete contoller and chan initilzation
++ */
++int intel_qrk_dma_probe(struct pci_dev *pdev,
++ struct middma_device *device)
++{
++ u32 base_addr, bar_size;
++ int err;
++
++ dev_info(&pdev->dev, "MDMA: probe for %x\n", pdev->device);
++ dev_info(&pdev->dev, "MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
++ device->max_chan, device->chan_base,
++ device->block_size, device->pimr_mask);
++
++ device->pdev = pci_dev_get(pdev);
++
++ base_addr = pci_resource_start(pdev, 1);
++ bar_size = pci_resource_len(pdev, 1);
++ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
++ if (!device->dma_base) {
++ pr_err("ERR_MDMA:ioremap failed\n");
++ err = -ENOMEM;
++ goto err_ioremap;
++ }
++
++ dev_info(&pdev->dev, "Remapped BAR 0x%08x to virt 0x%p\n",
++ base_addr, device->dma_base);
++
++ err = mid_setup_dma(pdev, device);
++ if (err)
++ goto err_dma;
++
++ return 0;
++
++err_dma:
++ iounmap(device->dma_base);
++err_ioremap:
++ pr_err("ERR_MDMA:Probe failed %d\n", err);
++ return err;
++}
++EXPORT_SYMBOL(intel_qrk_dma_probe);
++
++/**
++ * intel_mid_dma_remove - PCI remove
++ * @pdev: Controller PCI device structure
++ *
++ * Free up all resources and data
++ * Call shutdown_dma to complete contoller and chan cleanup
++ */
++void intel_qrk_dma_remove(struct pci_dev *pdev, struct middma_device *device)
++{
++ //middma_shutdown(pdev, device);
++}
++EXPORT_SYMBOL(intel_qrk_dma_remove);
++
++/* Power Management */
++/*
++* dma_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++int intel_qrk_dma_suspend(struct middma_device *device)
++{
++ int i = 0;
++ pr_debug("MDMA: dma_suspend called\n");
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++#if 0
++ dmac1_mask_periphral_intr(device);
++#endif
++ device->state = SUSPENDED;
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_dma_suspend);
++
++/**
++* dma_resume - PCI resume function
++*
++* @pci: PCI device structure
++*
++* This function is called by OS when a power event occurs
++*/
++int intel_qrk_dma_resume(struct middma_device *device)
++{
++ //return middma_resume(device);
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_dma_resume);
++
++static int intel_qrk_dma_runtime_suspend(struct middma_device *device)
++{
++ device->state = SUSPENDED;
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_dma_runtime_suspend);
++
++static int intel_qrk_dma_runtime_resume(struct middma_device *device)
++{
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++EXPORT_SYMBOL(intel_qrk_dma_runtime_resume);
++
++
+diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
+index 733f22c..5f85dde 100644
+--- a/drivers/tty/serial/8250/8250.c
++++ b/drivers/tty/serial/8250/8250.c
+@@ -561,6 +561,59 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
+ }
+ }
+
++/* Uart divisor latch read */
++static inline int _serial_dl_read(struct uart_8250_port *up)
++{
++ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
++}
++
++/* Uart divisor latch write */
++static inline void _serial_dl_write(struct uart_8250_port *up, int value)
++{
++ serial_out(up, UART_DLL, value & 0xff);
++ serial_out(up, UART_DLM, value >> 8 & 0xff);
++}
++
++#if defined(CONFIG_MIPS_ALCHEMY)
++/* Au1x00 haven't got a standard divisor latch */
++static int serial_dl_read(struct uart_8250_port *up)
++{
++ if (up->port.iotype == UPIO_AU)
++ return __raw_readl(up->port.membase + 0x28);
++ else
++ return _serial_dl_read(up);
++}
++
++static void serial_dl_write(struct uart_8250_port *up, int value)
++{
++ if (up->port.iotype == UPIO_AU)
++ __raw_writel(value, up->port.membase + 0x28);
++ else
++ _serial_dl_write(up, value);
++}
++#elif defined(CONFIG_SERIAL_8250_RM9K)
++static int serial_dl_read(struct uart_8250_port *up)
++{
++ return (up->port.iotype == UPIO_RM9000) ?
++ (((__raw_readl(up->port.membase + 0x10) << 8) |
++ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
++ _serial_dl_read(up);
++}
++
++static void serial_dl_write(struct uart_8250_port *up, int value)
++{
++ if (up->port.iotype == UPIO_RM9000) {
++ __raw_writel(value, up->port.membase + 0x08);
++ __raw_writel(value >> 8, up->port.membase + 0x10);
++ } else {
++ _serial_dl_write(up, value);
++ }
++}
++#else
++#define serial_dl_read(up) _serial_dl_read(up)
++#define serial_dl_write(up, value) _serial_dl_write(up, value)
++#endif
++
+ /*
+ * For the 16C950
+ */
+diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
+index 5cdb092..c78da53 100644
+--- a/drivers/tty/serial/8250/8250_pci.c
++++ b/drivers/tty/serial/8250/8250_pci.c
+@@ -27,7 +27,13 @@
+
+ #include "8250.h"
+
+-#undef SERIAL_DEBUG_PCI
++/* QUARK FPGA */
++#define SERIAL_DEBUG_PCI
++
++/* TODO: Bryan remove ! */
++static unsigned int quark_enable_msi = 0;
++module_param(quark_enable_msi, uint, 0644);
++MODULE_PARM_DESC(quark_enable_msi, "Enable MSI operation on Quark 8250-PCI");
+
+ /*
+ * init function returns:
+@@ -156,6 +162,20 @@ afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
+ }
+
+ /*
++ * UART parameters for Intel Quark setup
++ */
++static int
++pci_intel_qrk_setup(struct serial_private *priv,
++ const struct pciserial_board *board,
++ struct uart_8250_port *port, int idx)
++{
++ unsigned int bar, offset = board->first_offset;
++ bar = FL_GET_BASE(board->flags);
++
++ return setup_port(priv, port, bar, offset, board->reg_shift);
++}
++
++/*
+ * HP's Remote Management Console. The Diva chip came in several
+ * different versions. N-class, L2000 and A500 have two Diva chips, each
+ * with 3 UARTs (the third UART on the second chip is unused). Superdome
+@@ -1410,6 +1430,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
+ .subdevice = PCI_ANY_ID,
+ .setup = kt_serial_setup,
+ },
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = 0x0936,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .setup = pci_intel_qrk_setup,
++ },
++
+ /*
+ * ITE
+ */
+@@ -2139,6 +2167,8 @@ enum pci_board_num_t {
+ pbn_oxsemi_2_4000000,
+ pbn_oxsemi_4_4000000,
+ pbn_oxsemi_8_4000000,
++ pbn_intel_cb,
++ pbn_intel_qrk,
+ pbn_intel_i960,
+ pbn_sgi_ioc3,
+ pbn_computone_4,
+@@ -2725,6 +2755,12 @@ static struct pciserial_board pci_boards[] = {
+ .reg_shift = 2,
+ .first_offset = 0x10000,
+ },
++ [pbn_intel_qrk] = {
++ .flags = FL_BASE0,
++ .num_ports = 1,
++ .base_baud = 2764800,
++ .reg_shift = 2,
++ },
+ [pbn_sgi_ioc3] = {
+ .flags = FL_BASE0|FL_NOIRQ,
+ .num_ports = 1,
+@@ -3187,6 +3223,14 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
+ if (rc)
+ return rc;
+
++ /* TODO: Bryan remove ! */
++ if(quark_enable_msi == 1){
++ if(pci_enable_msi(dev)!=0){
++ printk(KERN_ERR "QUARK/DEBUG unable to enable MSIs on serial port!\n");
++ }
++ }
++
++
+ if (ent->driver_data == pbn_default) {
+ /*
+ * Use a copy of the pci_board entry for this;
+@@ -3998,6 +4042,12 @@ static struct pci_device_id serial_pci_tbl[] = {
+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_bt_2_115200 },
++ /*
++ * Quark descriptor
++ */
++ { PCI_VENDOR_ID_INTEL, 0x0936,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++ pbn_intel_qrk },
+
+ /*
+ * EKF addition for i960 Boards form EKF with serial port
+diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
+index 02e706e..a8f5d91 100644
+--- a/drivers/tty/serial/Kconfig
++++ b/drivers/tty/serial/Kconfig
+@@ -1327,6 +1327,26 @@ config SERIAL_IFX6X60
+ help
+ Support for the IFX6x60 modem devices on Intel MID platforms.
+
++config SERIAL_QUARK_UART
++ tristate "Quark High Speed UART support"
++ depends on PCI
++ select SERIAL_CORE
++ select DMADEVICES
++ select INTEL_MID_DMAC
++ help
++ This driver is for Intel(R) Quark X1000 UART with DMA enabled.
++ If you don't want DMA then you should use the standard 8250_pci
++ driver.
++
++config SERIAL_QUARK_UART_CONSOLE
++ bool "Support for console on Intel(R) Quark X1000 UART"
++ depends on SERIAL_QUARK_UART=y
++ select SERIAL_CORE_CONSOLE
++ help
++ Say Y here if you wish to use the Quark UART as the system console
++ (the system console is the device which receives all kernel messages and
++ warnings and which allows logins in single user mode).
++
+ config SERIAL_PCH_UART
+ tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
+ depends on PCI
+diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
+index df1b998..ccbc063 100644
+--- a/drivers/tty/serial/Makefile
++++ b/drivers/tty/serial/Makefile
+@@ -74,6 +74,7 @@ obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
+ obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
+ obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
+ obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
++obj-$(CONFIG_SERIAL_QUARK_UART) += intel_quark_uart.o
+ obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
+ 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
+--- /dev/null
++++ b/drivers/tty/serial/intel_quark_uart.c
+@@ -0,0 +1,2032 @@
++/*
++ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
++ *Copyright (C) 2014 Intel Corporation.
++ *
++ *This program is free software; you can redistribute it and/or modify
++ *it under the terms of the GNU General Public License as published by
++ *the Free Software Foundation; version 2 of the License.
++ *
++ *This program is distributed in the hope that it will be useful,
++ *but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ *GNU General Public License for more details.
++ *
++ *You should have received a copy of the GNU General Public License
++ *along with this program; if not, write to the Free Software
++ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
++ */
++#if defined(CONFIG_SERIAL_QUARK_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++#include <asm/qrk.h>
++#endif
++#include <linux/kernel.h>
++#include <linux/serial_reg.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/console.h>
++#include <linux/serial_core.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/dmi.h>
++#include <linux/nmi.h>
++#include <linux/delay.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/debugfs.h>
++#include <linux/dmaengine.h>
++
++enum {
++ QUARK_UART_HANDLED_RX_INT_SHIFT,
++ QUARK_UART_HANDLED_TX_INT_SHIFT,
++ QUARK_UART_HANDLED_RX_ERR_INT_SHIFT,
++ QUARK_UART_HANDLED_RX_TRG_INT_SHIFT,
++ QUARK_UART_HANDLED_MS_INT_SHIFT,
++ QUARK_UART_HANDLED_LS_INT_SHIFT,
++};
++
++enum {
++ QUARK_UART_8LINE,
++ QUARK_UART_2LINE,
++};
++
++#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), \
++ })
++
++#define QUARK_UART_DRIVER_DEVICE "ttyQRK"
++#define QUARK_UART_FIFO_LEN 16
++//#define __QRK_DMA_DEBUG /* TODO: remove all code of this type */
++
++/* Set the max number of UART port
++ * Intel EG20T QUARK: 4 port
++ * LAPIS Semiconductor ML7213 IOH: 3 port
++ * LAPIS Semiconductor ML7223 IOH: 2 port
++*/
++#define QUARK_UART_NR 2
++
++#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<<((\
++ QUARK_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
++#define QUARK_UART_HANDLED_RX_TRG_INT (1<<((\
++ QUARK_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
++#define QUARK_UART_HANDLED_MS_INT (1<<((QUARK_UART_HANDLED_MS_INT_SHIFT)<<1))
++
++#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_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_IID 0x00000006
++#define QUARK_UART_IIR_MSI 0x00000000
++#define QUARK_UART_IIR_TRI 0x00000002
++#define QUARK_UART_IIR_RRI 0x00000004
++#define QUARK_UART_IIR_REI 0x00000006
++#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_FCR_FIFOE 0x00000001
++#define QUARK_UART_FCR_RFR 0x00000002
++#define QUARK_UART_FCR_TFR 0x00000004
++#define QUARK_UART_FCR_DMS 0x00000008
++#define QUARK_UART_FCR_FIFO256 0x00000020
++#define QUARK_UART_FCR_RFTL 0x000000C0
++
++#define QUARK_UART_FCR_RFTL1 0x00000000
++#define QUARK_UART_FCR_RFTL64 0x00000040
++#define QUARK_UART_FCR_RFTL128 0x00000080
++#define QUARK_UART_FCR_RFTL224 0x000000C0
++#define QUARK_UART_FCR_RFTL16 QUARK_UART_FCR_RFTL64
++#define QUARK_UART_FCR_RFTL32 QUARK_UART_FCR_RFTL128
++#define QUARK_UART_FCR_RFTL56 QUARK_UART_FCR_RFTL224
++#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_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_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)
++
++#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_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_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_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_MS (QUARK_UART_IIR_MSI)
++
++#define QUARK_UART_HAL_PARITY_NONE (QUARK_UART_LCR_NP)
++#define QUARK_UART_HAL_PARITY_ODD (QUARK_UART_LCR_OP)
++#define QUARK_UART_HAL_PARITY_EVEN (QUARK_UART_LCR_EP)
++#define QUARK_UART_HAL_PARITY_FIX1 (QUARK_UART_LCR_1P)
++#define QUARK_UART_HAL_PARITY_FIX0 (QUARK_UART_LCR_0P)
++#define QUARK_UART_HAL_5BIT (QUARK_UART_LCR_5BIT)
++#define QUARK_UART_HAL_6BIT (QUARK_UART_LCR_6BIT)
++#define QUARK_UART_HAL_7BIT (QUARK_UART_LCR_7BIT)
++#define QUARK_UART_HAL_8BIT (QUARK_UART_LCR_8BIT)
++#define QUARK_UART_HAL_STB1 0
++#define QUARK_UART_HAL_STB2 (QUARK_UART_LCR_STB)
++
++#define QUARK_UART_HAL_CLR_TX_FIFO (QUARK_UART_FCR_TFR)
++#define QUARK_UART_HAL_CLR_RX_FIFO (QUARK_UART_FCR_RFR)
++#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_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_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_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_MS_INT (QUARK_UART_IER_EDSSI)
++#define QUARK_UART_HAL_ALL_INT (QUARK_UART_IER_MASK)
++
++#define QUARK_UART_HAL_DTR (QUARK_UART_MCR_DTR)
++#define QUARK_UART_HAL_RTS (QUARK_UART_MCR_RTS)
++#define QUARK_UART_HAL_OUT (QUARK_UART_MCR_OUT)
++#define QUARK_UART_HAL_LOOP (QUARK_UART_MCR_LOOP)
++#define QUARK_UART_HAL_AFE (QUARK_UART_MCR_AFE)
++
++#define PCI_VENDOR_ID_ROHM 0x10DB
++
++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
++
++#define DEFAULT_UARTCLK 44236800 /* 2.76 MHz * 16 */
++
++/**
++ * struct inel_qrk_uart_buffer
++ *
++ * Descriptor for a UART bufer
++ */
++struct quark_uart_buffer {
++ dma_addr_t dma_addr;
++ unsigned char *buf;
++ u32 offs;
++ int size;
++};
++
++struct x1000_port {
++ struct uart_port port;
++ int port_type;
++ void __iomem *membase;
++ resource_size_t mapbase;
++ struct pci_dev *pdev;
++ int fifo_size;
++ unsigned int uartclk;
++ int start_tx;
++ int start_rx;
++ int tx_empty;
++ int trigger;
++ int trigger_level;
++ unsigned int dmsr;
++ unsigned int fcr;
++ unsigned int mcr;
++ unsigned int 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 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;
++
++ /* protect the x1000_port private structure and io access to membase */
++ spinlock_t lock;
++};
++
++/**
++ * struct quark_uart_driver_data - private data structure for UART-DMA
++ * @port_type: The number of DMA channel
++ * @line_no: UART port line number (0, 1, 2...)
++ */
++struct quark_uart_driver_data {
++ int port_type;
++ int line_no;
++};
++
++#if 0
++static unsigned int mem_serial_in(struct uart_port *p, int offset)
++{
++ offset = offset << p->regshift;
++ return readb(p->membase + offset);
++}
++
++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
++ *
++ * @param up: pointer to uart descriptor
++ * @param offset: register offset
++ *
++ * Reads a register @ offset
++ */
++static inline unsigned int serial_in(struct x1000_port *up, int offset)
++{
++ int soffset = offset << 2;
++
++ return (unsigned int)readb(up->membase + soffset);
++}
++
++/**
++ * serial_out
++ *
++ * @param up: pointer to uart descriptor
++ * @param offset: register offset
++ *
++ * Writes a register @ offset
++ */
++static inline void serial_out(struct x1000_port *up, int offset, int value)
++{
++ unsigned char val = value & 0xff;
++ int soffset = offset << 2;
++
++ writeb(val, up->membase + soffset);
++}
++
++#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
++static struct x1000_port *quark_uart_ports[QUARK_UART_NR];
++#endif
++static unsigned int default_baud = 115200;
++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 };
++static const int trigger_level_1[4] = { 1, 1, 1, 1 };
++
++#ifdef CONFIG_DEBUG_FS
++
++#define QUARK_REGS_BUFSIZE 1024
++
++
++static ssize_t port_show_regs(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct x1000_port *priv = file->private_data;
++ char *buf;
++ u32 len = 0;
++ ssize_t ret;
++ unsigned char lcr;
++
++ buf = kzalloc(QUARK_REGS_BUFSIZE, GFP_KERNEL);
++ if (!buf)
++ return 0;
++
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "QUARK X1000 port[%d] regs:\n", priv->port.line);
++
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "=================================\n");
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "IER: \t0x%02x\n", serial_in(priv, UART_IER));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "IIR: \t0x%02x\n", serial_in(priv, UART_IIR));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "LCR: \t0x%02x\n", serial_in(priv, UART_LCR));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "MCR: \t0x%02x\n", serial_in(priv, UART_MCR));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "LSR: \t0x%02x\n", serial_in(priv, UART_LSR));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "MSR: \t0x%02x\n", serial_in(priv, UART_MSR));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "BRCSR: \t0x%02x\n",
++ serial_in(priv, QUARK_UART_BRCSR));
++
++ lcr = serial_in(priv, UART_LCR);
++ serial_out(priv, UART_LCR, QUARK_UART_LCR_DLAB);
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "DLL: \t0x%02x\n", serial_in(priv, UART_DLL));
++ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
++ "DLM: \t0x%02x\n", serial_in(priv, UART_DLM));
++ serial_out(priv, UART_LCR, lcr);
++
++ if (len > QUARK_REGS_BUFSIZE)
++ len = QUARK_REGS_BUFSIZE;
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++ kfree(buf);
++ return ret;
++}
++
++static const struct file_operations port_regs_ops = {
++ .owner = THIS_MODULE,
++ .open = simple_open,
++ .read = port_show_regs,
++ .llseek = default_llseek,
++};
++#endif /* CONFIG_DEBUG_FS */
++
++/* Return UART clock, checking for board specific clocks. */
++static unsigned int quark_uart_get_uartclk(void)
++{
++ return DEFAULT_UARTCLK;
++}
++
++static void quark_uart_hal_enable_interrupt(struct x1000_port *priv,
++ 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;
++ 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);
++ serial_out(priv, UART_IER, ier);
++}
++
++static int quark_uart_hal_set_line(struct x1000_port *priv, unsigned int baud,
++ unsigned int parity, unsigned int bits,
++ unsigned int stb)
++{
++ unsigned int dll, dlm, lcr;
++ int div;
++
++ div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud);
++ if (div < 0 || USHRT_MAX <= div) {
++ dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
++ return -EINVAL;
++ }
++
++ dll = (unsigned int)div & 0x00FFU;
++ dlm = ((unsigned int)div >> 8) & 0x00FFU;
++
++ if (parity & ~(QUARK_UART_LCR_PEN | QUARK_UART_LCR_EPS | QUARK_UART_LCR_SP)) {
++ dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity);
++ return -EINVAL;
++ }
++
++ if (bits & ~QUARK_UART_LCR_WLS) {
++ dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits);
++ return -EINVAL;
++ }
++
++ if (stb & ~QUARK_UART_LCR_STB) {
++ dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb);
++ return -EINVAL;
++ }
++
++ lcr = parity;
++ 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);
++ serial_out(priv, UART_LCR, lcr);
++
++ return 0;
++}
++
++static int quark_uart_hal_fifo_reset(struct x1000_port *priv,
++ unsigned int flag)
++{
++ if (flag & ~(QUARK_UART_FCR_TFR | QUARK_UART_FCR_RFR)) {
++ dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n",
++ __func__, flag);
++ return -EINVAL;
++ }
++
++ serial_out(priv, UART_FCR, QUARK_UART_FCR_FIFOE | priv->fcr);
++ serial_out(priv,
++ UART_FCR, QUARK_UART_FCR_FIFOE | priv->fcr | flag);
++ serial_out(priv, UART_FCR, priv->fcr);
++
++ return 0;
++}
++
++static int quark_uart_hal_set_fifo(struct x1000_port *priv,
++ unsigned int dmamode,
++ unsigned int fifo_size, unsigned int trigger)
++{
++ u8 fcr;
++
++ if (dmamode & ~QUARK_UART_FCR_DMS) {
++ dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n",
++ __func__, dmamode);
++ return -EINVAL;
++ }
++
++ if (fifo_size & ~(QUARK_UART_FCR_FIFOE | QUARK_UART_FCR_FIFO256)) {
++ dev_err(priv->port.dev, "%s:Invalid FIFO SIZE(0x%x)\n",
++ __func__, fifo_size);
++ return -EINVAL;
++ }
++
++ if (trigger & ~QUARK_UART_FCR_RFTL) {
++ dev_err(priv->port.dev, "%s:Invalid TRIGGER(0x%x)\n",
++ __func__, trigger);
++ return -EINVAL;
++ }
++
++ switch (priv->fifo_size) {
++ case 256:
++ priv->trigger_level =
++ trigger_level_256[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
++ break;
++ case 64:
++ priv->trigger_level =
++ trigger_level_64[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
++ break;
++ case 16:
++ priv->trigger_level =
++ trigger_level_16[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
++ break;
++ default:
++ priv->trigger_level =
++ 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;
++}
++
++static u8 quark_uart_hal_get_modem(struct x1000_port *priv)
++{
++ unsigned int msr = serial_in(priv, UART_MSR);
++ priv->dmsr = msr & QUARK_UART_MSR_DELTA;
++ return (u8)msr;
++}
++
++static void quark_uart_hal_write(struct x1000_port *priv,
++ const unsigned char *buf, int tx_size)
++{
++ int i;
++ unsigned int thr;
++
++ for (i = 0; i < tx_size;) {
++ thr = buf[i++];
++ serial_out(priv, QUARK_UART_THR, thr);
++ }
++}
++
++static int quark_uart_hal_read(struct x1000_port *priv, unsigned char *buf,
++ int rx_size)
++{
++ int i;
++ u8 rbr, lsr;
++ struct uart_port *port = &priv->port;
++
++ lsr = serial_in(priv, UART_LSR);
++ for (i = 0, lsr = serial_in(priv, UART_LSR);
++ i < rx_size && lsr & (UART_LSR_DR | UART_LSR_BI);
++ lsr = serial_in(priv, UART_LSR)) {
++ rbr = serial_in(priv, QUARK_UART_RBR);
++
++ if (lsr & UART_LSR_BI) {
++ port->icount.brk++;
++ if (uart_handle_break(port))
++ continue;
++ }
++#ifdef SUPPORT_SYSRQ
++ if (port->sysrq) {
++ if (uart_handle_sysrq_char(port, rbr))
++ continue;
++ }
++#endif
++
++ buf[i++] = rbr;
++ }
++ return i;
++}
++
++static unsigned char quark_uart_hal_get_iid(struct x1000_port *priv)
++{
++ return serial_in(priv, UART_IIR) &\
++ (QUARK_UART_IIR_IID | QUARK_UART_IIR_TOI | QUARK_UART_IIR_IP);
++}
++
++static u8 quark_uart_hal_get_line_status(struct x1000_port *priv)
++{
++ return serial_in(priv, UART_LSR);
++}
++
++static void quark_uart_hal_set_break(struct x1000_port *priv, int on)
++{
++ unsigned int lcr;
++
++ lcr = serial_in(priv, UART_LCR);
++ if (on)
++ lcr |= QUARK_UART_LCR_SB;
++ else
++ lcr &= ~QUARK_UART_LCR_SB;
++
++ serial_out(priv, UART_LCR, lcr);
++}
++
++static int push_rx(struct x1000_port *priv, const unsigned char *buf,
++ int size)
++{
++ struct uart_port *port = &priv->port;
++ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
++
++ tty_insert_flip_string(tty, buf, size);
++ tty_flip_buffer_push(tty);
++
++ return 0;
++}
++
++static int pop_tx_x(struct x1000_port *priv, unsigned char *buf)
++{
++ int ret = 0;
++ struct uart_port *port = &priv->port;
++
++ if (port->x_char) {
++ dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n",
++ __func__, port->x_char, jiffies);
++ buf[0] = port->x_char;
++ port->x_char = 0;
++ ret = 1;
++ }
++
++ return ret;
++}
++
++static int dma_push_rx(struct x1000_port *priv, int size)
++{
++ int room;
++ struct uart_port *port = &priv->port;
++ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
++
++ room = tty_buffer_request_room(tty, size);
++
++ if (room < size)
++ dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
++ size - room);
++ if (!room)
++ return 0;
++
++ tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
++
++ port->icount.rx += room;
++
++ 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;
++ struct uart_port *port = &priv->port;
++ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
++ int count;
++
++ dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE);
++ count = dma_push_rx(priv, priv->trigger_level);
++ if (count)
++ tty_flip_buffer_push(tty);
++ async_tx_ack(priv->desc_rx);
++ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_RX_INT |
++ QUARK_UART_HAL_RX_ERR_INT);
++}
++
++static void quark_dma_tx_complete(void *arg)
++{
++ struct x1000_port *priv = arg;
++ struct uart_port *port = &priv->port;
++ struct circ_buf *xmit = &port->state->xmit;
++ struct scatterlist *sg = priv->sg_tx_p;
++ int i;
++
++ 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;
++ 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;
++ kfree(priv->sg_tx_p);
++ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++}
++
++static int pop_tx(struct x1000_port *priv, int size)
++{
++ int count = 0;
++ struct uart_port *port = &priv->port;
++ struct circ_buf *xmit = &port->state->xmit;
++
++ if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
++ goto pop_tx_end;
++
++ do {
++ int cnt_to_end =
++ CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
++ int sz = min(size - count, cnt_to_end);
++ quark_uart_hal_write(priv, &xmit->buf[xmit->tail], sz);
++ xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
++ count += sz;
++ } while (!uart_circ_empty(xmit) && count < size);
++
++pop_tx_end:
++ dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n",
++ count, size - count, jiffies);
++
++ return count;
++}
++
++static int handle_rx_to(struct x1000_port *priv)
++{
++ struct quark_uart_buffer *buf;
++ int rx_size;
++ int ret;
++ if (!priv->start_rx) {
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_RX_INT |
++ QUARK_UART_HAL_RX_ERR_INT);
++ return 0;
++ }
++ buf = &priv->rxbuf;
++ do {
++ rx_size = quark_uart_hal_read(priv, buf->buf, buf->size);
++ ret = push_rx(priv, buf->buf, rx_size);
++ if (ret)
++ return 0;
++ } while (rx_size == buf->size);
++
++ return QUARK_UART_HANDLED_RX_INT;
++}
++
++static int handle_rx(struct x1000_port *priv)
++{
++ return handle_rx_to(priv);
++}
++
++static int dma_handle_rx(struct x1000_port *priv)
++{
++ struct uart_port *port = &priv->port;
++ struct dma_async_tx_descriptor *desc;
++ struct scatterlist *sg;
++
++ priv = container_of(port, struct x1000_port, port);
++ sg = &priv->sg_rx;
++
++ sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
++
++ sg_dma_len(sg) = priv->trigger_level;
++
++ sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
++ sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
++ ~PAGE_MASK);
++
++ 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);
++
++ if (!desc)
++ return 0;
++
++ priv->desc_rx = desc;
++ desc->callback = quark_dma_rx_complete;
++ desc->callback_param = priv;
++ desc->tx_submit(desc);
++ dma_async_issue_pending(priv->chan_rx);
++
++ return QUARK_UART_HANDLED_RX_INT;
++}
++
++static unsigned int handle_tx(struct x1000_port *priv)
++{
++ struct uart_port *port = &priv->port;
++ struct circ_buf *xmit = &port->state->xmit;
++ int fifo_size;
++ int tx_size;
++ int size;
++ int tx_empty;
++
++ if (!priv->start_tx) {
++ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
++ __func__, jiffies);
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ priv->tx_empty = 1;
++ return 0;
++ }
++
++ fifo_size = max(priv->fifo_size, 1);
++ tx_empty = 1;
++ if (pop_tx_x(priv, xmit->buf)) {
++ quark_uart_hal_write(priv, xmit->buf, 1);
++ port->icount.tx++;
++ tx_empty = 0;
++ fifo_size--;
++ }
++ size = min(xmit->head - xmit->tail, fifo_size);
++ if (size < 0)
++ size = fifo_size;
++
++ tx_size = pop_tx(priv, size);
++ if (tx_size > 0) {
++ port->icount.tx += tx_size;
++ tx_empty = 0;
++ }
++
++ priv->tx_empty = tx_empty;
++
++ if (tx_empty) {
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ 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;
++ struct circ_buf *xmit = &port->state->xmit;
++ struct scatterlist *sg;
++ int nent;
++ int fifo_size;
++ int tx_empty;
++ struct dma_async_tx_descriptor *desc;
++ int num;
++ int i;
++ int bytes;
++ int size;
++ int rem;
++
++ if (!priv->start_tx) {
++ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
++ __func__, jiffies);
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
++ priv->tx_empty = 1;
++ return 0;
++ }
++
++ if (priv->tx_dma_use) {
++ 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);
++ priv->tx_empty = 1;
++ return 0;
++ }
++
++ fifo_size = max(priv->fifo_size, 1);
++ tx_empty = 1;
++ if (pop_tx_x(priv, xmit->buf)) {
++ quark_uart_hal_write(priv, xmit->buf, 1);
++ port->icount.tx++;
++ tx_empty = 0;
++ fifo_size--;
++ }
++
++ 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);
++ return 0;
++ }
++
++ if (bytes > fifo_size) {
++ num = bytes / fifo_size + 1;
++ size = fifo_size;
++ rem = bytes % fifo_size;
++ } else {
++ num = 1;
++ size = bytes;
++ rem = bytes;
++ }
++
++ dev_dbg(priv->port.dev, "%s num=%d size=%d rem=%d\n",
++ __func__, num, size, rem);
++
++ priv->tx_dma_use = 1;
++
++ priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
++ if (!priv->sg_tx_p) {
++ dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__);
++ return 0;
++ }
++
++ sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
++ sg = priv->sg_tx_p;
++
++ for (i = 0; i < num; i++, sg++) {
++ if (i == (num - 1))
++ sg_set_page(sg, virt_to_page(xmit->buf),
++ rem, fifo_size * i);
++ else
++ sg_set_page(sg, virt_to_page(xmit->buf),
++ size, fifo_size * i);
++ }
++
++ sg = priv->sg_tx_p;
++ nent = dma_map_sg(port->dev, sg, num, DMA_TO_DEVICE);
++ if (!nent) {
++ dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__);
++ return 0;
++ }
++ priv->nent = nent;
++
++ for (i = 0; i < nent; i++, sg++) {
++ sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) +
++ 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;
++ else
++ sg_dma_len(sg) = 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);
++
++ return QUARK_UART_HANDLED_TX_INT;
++}
++
++static void quark_uart_err_ir(struct x1000_port *priv, unsigned int lsr)
++{
++ struct uart_port *port = &priv->port;
++ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
++ char *error_msg[5] = {};
++ int i = 0;
++
++ if (lsr & QUARK_UART_LSR_ERR)
++ error_msg[i++] = "Error data in FIFO\n";
++
++ if (lsr & UART_LSR_FE) {
++ port->icount.frame++;
++ error_msg[i++] = " Framing Error\n";
++ }
++
++ if (lsr & UART_LSR_PE) {
++ port->icount.parity++;
++ error_msg[i++] = " Parity Error\n";
++ }
++
++ if (lsr & UART_LSR_OE) {
++ port->icount.overrun++;
++ error_msg[i++] = " Overrun Error\n";
++ }
++
++ if (tty == NULL) {
++ for (i = 0; error_msg[i] != NULL; i++)
++ dev_err(&priv->pdev->dev, error_msg[i]);
++ } else {
++ tty_kref_put(tty);
++ }
++}
++
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define mask_pvm(x) qrk_pci_pvm_mask(x)
++ #define unmask_pvm(x) qrk_pci_pvm_unmask(x)
++#else
++ #define mask_pvm(x)
++ #define unmask_pvm(x)
++#endif
++
++static irqreturn_t quark_uart_interrupt(int irq, void *dev_id)
++{
++ struct x1000_port *priv = dev_id;
++ unsigned int handled;
++ u8 lsr;
++ int ret = 0;
++ unsigned char iid;
++ unsigned long flags;
++ int next = 1;
++ u8 msr;
++
++ spin_lock_irqsave(&priv->lock, flags);
++ handled = 0;
++ while (next) {
++ iid = quark_uart_hal_get_iid(priv);
++ if (iid & QUARK_UART_IIR_IP) /* No Interrupt */
++ break;
++ switch (iid) {
++ case QUARK_UART_IID_RLS: /* Receiver Line Status */
++ lsr = quark_uart_hal_get_line_status(priv);
++ if (lsr & (QUARK_UART_LSR_ERR | UART_LSR_FE |
++ UART_LSR_PE | UART_LSR_OE)) {
++ quark_uart_err_ir(priv, lsr);
++ ret = QUARK_UART_HANDLED_RX_ERR_INT;
++ } else {
++ ret = QUARK_UART_HANDLED_LS_INT;
++ }
++ 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);
++ }
++ break;
++ case QUARK_UART_IID_RDR_TO: /* Received Data Ready
++ (FIFO Timeout) */
++ ret = handle_rx_to(priv);
++ break;
++ case QUARK_UART_IID_THRE: /* Transmitter Holding Register
++ Empty */
++ if (priv->use_dma)
++
++ ret = dma_handle_tx(priv);
++ else
++ ret = handle_tx(priv);
++ break;
++ case QUARK_UART_IID_MS: /* Modem Status */
++ msr = quark_uart_hal_get_modem(priv);
++ next = 0; /* MS ir prioirty is the lowest. So, MS ir
++ means final interrupt */
++ if ((msr & UART_MSR_ANY_DELTA) == 0)
++ break;
++ ret |= QUARK_UART_HANDLED_MS_INT;
++ break;
++ default: /* Never junp to this label */
++ dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
++ iid, jiffies);
++ ret = -1;
++ next = 0;
++ break;
++ }
++ handled |= (unsigned int)ret;
++ }
++
++ spin_unlock_irqrestore(&priv->lock, flags);
++
++ return IRQ_RETVAL(handled);
++}
++
++/* This function tests whether the transmitter fifo and shifter for the port
++ described by 'port' is empty. */
++static unsigned int quark_uart_tx_empty(struct uart_port *port)
++{
++ struct x1000_port *priv;
++
++ priv = container_of(port, struct x1000_port, port);
++ if (priv->tx_empty)
++ return TIOCSER_TEMT;
++ else
++ return 0;
++}
++
++/* Returns the current state of modem control inputs. */
++static unsigned int quark_uart_get_mctrl(struct uart_port *port)
++{
++ struct x1000_port *priv;
++ u8 modem;
++ unsigned int ret = 0;
++
++ priv = container_of(port, struct x1000_port, port);
++ modem = quark_uart_hal_get_modem(priv);
++
++ if (modem & UART_MSR_DCD)
++ ret |= TIOCM_CAR;
++
++ if (modem & UART_MSR_RI)
++ ret |= TIOCM_RNG;
++
++ if (modem & UART_MSR_DSR)
++ ret |= TIOCM_DSR;
++
++ if (modem & UART_MSR_CTS)
++ ret |= TIOCM_CTS;
++
++ return ret;
++}
++
++static void quark_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++ u32 mcr = 0;
++ struct x1000_port *priv = container_of(port, struct x1000_port, port);
++
++ if (mctrl & TIOCM_DTR)
++ mcr |= UART_MCR_DTR;
++ if (mctrl & TIOCM_RTS)
++ mcr |= UART_MCR_RTS;
++ if (mctrl & TIOCM_LOOP)
++ mcr |= UART_MCR_LOOP;
++
++ if (priv->mcr & UART_MCR_AFE)
++ mcr |= UART_MCR_AFE;
++
++ if (mctrl)
++ serial_out(priv, UART_MCR, mcr);
++}
++
++static void quark_uart_stop_tx(struct uart_port *port)
++{
++ struct x1000_port *priv;
++ priv = container_of(port, struct x1000_port, port);
++ priv->start_tx = 0;
++ priv->tx_dma_use = 0;
++}
++
++static void quark_uart_start_tx(struct uart_port *port)
++{
++ struct x1000_port *priv;
++
++ priv = container_of(port, struct x1000_port, port);
++
++ if (priv->use_dma) {
++ if (priv->tx_dma_use) {
++ dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n",
++ __func__);
++ return;
++ }
++ }
++
++#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);
++}
++
++static void quark_uart_stop_rx(struct uart_port *port)
++{
++ struct x1000_port *priv;
++
++ priv = container_of(port, struct x1000_port, port);
++ 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);
++}
++
++/* Enable the modem status interrupts. */
++static void quark_uart_enable_ms(struct uart_port *port)
++{
++ struct x1000_port *priv;
++ priv = container_of(port, struct x1000_port, port);
++ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_MS_INT);
++}
++
++/* Control the transmission of a break signal. */
++static void quark_uart_break_ctl(struct uart_port *port, int ctl)
++{
++ struct x1000_port *priv;
++ unsigned long flags;
++
++ priv = container_of(port, struct x1000_port, port);
++ spin_lock_irqsave(&priv->lock, flags);
++ quark_uart_hal_set_break(priv, ctl);
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++/* Grab any interrupt resources and initialise any low level driver state. */
++static int quark_uart_startup(struct uart_port *port)
++{
++ struct x1000_port *priv;
++ int ret;
++ int fifo_size;
++ int trigger_level;
++
++ priv = container_of(port, struct x1000_port, port);
++ priv->tx_empty = 1;
++
++ if (port->uartclk)
++ 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,
++ QUARK_UART_HAL_STB1);
++
++ if (ret)
++ return ret;
++
++ switch (priv->fifo_size) {
++ case 256:
++ fifo_size = QUARK_UART_HAL_FIFO256;
++ break;
++ case 64:
++ fifo_size = QUARK_UART_HAL_FIFO64;
++ break;
++ case 16:
++ fifo_size = QUARK_UART_HAL_FIFO16;
++ break;
++ case 1:
++ default:
++ fifo_size = QUARK_UART_HAL_FIFO_DIS;
++ break;
++ }
++
++ switch (priv->trigger) {
++ case QUARK_UART_HAL_TRIGGER1:
++ trigger_level = 1;
++ break;
++ case QUARK_UART_HAL_TRIGGER_L:
++ trigger_level = priv->fifo_size / 4;
++ break;
++ case QUARK_UART_HAL_TRIGGER_M:
++ trigger_level = priv->fifo_size / 2;
++ break;
++ case QUARK_UART_HAL_TRIGGER_H:
++ default:
++ trigger_level = priv->fifo_size - (priv->fifo_size / 8);
++ break;
++ }
++
++ 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;
++}
++
++static void quark_uart_shutdown(struct uart_port *port)
++{
++ 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);
++ 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,
++ QUARK_UART_HAL_FIFO_DIS, QUARK_UART_HAL_TRIGGER1);
++ 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
++ *bits. Update read_status_mask and ignore_status_mask to indicate
++ *the types of events we are interested in receiving. */
++static void quark_uart_set_termios(struct uart_port *port,
++ struct ktermios *termios, struct ktermios *old)
++{
++ int rtn;
++ unsigned int baud, parity, bits, stb;
++ struct x1000_port *priv;
++ unsigned long flags;
++
++ priv = container_of(port, struct x1000_port, port);
++ switch (termios->c_cflag & CSIZE) {
++ case CS5:
++ bits = QUARK_UART_HAL_5BIT;
++ break;
++ case CS6:
++ bits = QUARK_UART_HAL_6BIT;
++ break;
++ case CS7:
++ bits = QUARK_UART_HAL_7BIT;
++ break;
++ default: /* CS8 */
++ bits = QUARK_UART_HAL_8BIT;
++ break;
++ }
++ if (termios->c_cflag & CSTOPB)
++ stb = QUARK_UART_HAL_STB2;
++ else
++ stb = QUARK_UART_HAL_STB1;
++
++ if (termios->c_cflag & PARENB) {
++ if (termios->c_cflag & PARODD)
++ parity = QUARK_UART_HAL_PARITY_ODD;
++ else
++ parity = QUARK_UART_HAL_PARITY_EVEN;
++
++ } else
++ parity = QUARK_UART_HAL_PARITY_NONE;
++
++ /* Only UART0 has auto hardware flow function */
++ if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
++ priv->mcr |= UART_MCR_AFE;
++ else
++ priv->mcr &= ~UART_MCR_AFE;
++
++ 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);
++
++ uart_update_timeout(port, termios->c_cflag, baud);
++ rtn = quark_uart_hal_set_line(priv, baud, parity, bits, stb);
++ if (rtn)
++ goto out;
++
++ quark_uart_set_mctrl(&priv->port, priv->port.mctrl);
++ /* Don't rewrite B0 */
++ if (tty_termios_baud_rate(termios))
++ tty_termios_encode_baud_rate(termios, baud, baud);
++
++out:
++ spin_unlock(&port->lock);
++ spin_unlock_irqrestore(&priv->lock, flags);
++}
++
++static const char *quark_uart_type(struct uart_port *port)
++{
++ return KBUILD_MODNAME;
++}
++
++static void quark_uart_release_port(struct uart_port *port)
++{
++ struct x1000_port *priv;
++
++ priv = container_of(port, struct x1000_port, port);
++ pci_iounmap(priv->pdev, priv->membase);
++ pci_release_regions(priv->pdev);
++}
++
++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;
++}
++
++static void quark_uart_config_port(struct uart_port *port, int type)
++{
++ 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;
++ quark_uart_request_port(port);
++ }
++}
++
++static int quark_uart_verify_port(struct uart_port *port,
++ 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;
++ 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 (!priv->use_dma)
++ quark_request_dma(port);
++ priv->use_dma = 1;
++ }
++
++ return 0;
++}
++
++#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_QUARK_UART_CONSOLE)
++/*
++ * Wait for transmitter & holding register to empty
++ */
++static void wait_for_xmitr(struct x1000_port *up, int bits)
++{
++ unsigned int status, tmout = 10000;
++
++ /* Wait up to 10ms for the character(s) to be sent. */
++ for (;;) {
++ status = serial_in(up, UART_LSR);
++
++ if ((status & bits) == bits)
++ break;
++ if (--tmout == 0)
++ break;
++ udelay(1);
++ }
++
++ /* Wait up to 1s for flow control if necessary */
++ if (up->port.flags & UPF_CONS_FLOW) {
++ unsigned int tmout;
++ for (tmout = 1000000; tmout; tmout--) {
++ unsigned int msr = serial_in(up, UART_MSR);
++ if (msr & UART_MSR_CTS)
++ break;
++ udelay(1);
++ touch_nmi_watchdog();
++ }
++ }
++}
++#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_QUARK_UART_CONSOLE */
++
++#ifdef CONFIG_CONSOLE_POLL
++/*
++ * Console polling routines for communicate via uart while
++ * in an interrupt or debug context.
++ */
++static int quark_uart_get_poll_char(struct uart_port *port)
++{
++ struct x1000_port *priv =
++ container_of(port, struct x1000_port, port);
++ u8 lsr = serial_in(priv, UART_LSR);
++
++ if (!(lsr & UART_LSR_DR))
++ return NO_POLL_CHAR;
++
++ return serial_in(priv, QUARK_UART_RBR);
++}
++
++
++static void quark_uart_put_poll_char(struct uart_port *port,
++ unsigned char c)
++{
++ unsigned int ier;
++ struct x1000_port *priv =
++ container_of(port, struct x1000_port, port);
++
++ /*
++ * First save the IER then disable the interrupts
++ */
++ ier = serial_in(priv, UART_IER);
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT);
++
++ wait_for_xmitr(priv, UART_LSR_THRE);
++ /*
++ * Send the character out.
++ * If a LF, also do CR...
++ */
++ serial_out(priv, QUARK_UART_THR, c);
++ if (c == 10) {
++ wait_for_xmitr(priv, UART_LSR_THRE);
++ serial_out(priv, QUARK_UART_THR, 13);
++ }
++
++ /*
++ * Finally, wait for transmitter to become empty
++ * and restore the IER
++ */
++ wait_for_xmitr(priv, BOTH_EMPTY);
++ serial_out(priv, UART_IER, ier);
++}
++#endif /* CONFIG_CONSOLE_POLL */
++
++static struct uart_ops quark_uart_ops = {
++ .tx_empty = quark_uart_tx_empty,
++ .set_mctrl = quark_uart_set_mctrl,
++ .get_mctrl = quark_uart_get_mctrl,
++ .stop_tx = quark_uart_stop_tx,
++ .start_tx = quark_uart_start_tx,
++ .stop_rx = quark_uart_stop_rx,
++ .enable_ms = quark_uart_enable_ms,
++ .break_ctl = quark_uart_break_ctl,
++ .startup = quark_uart_startup,
++ .shutdown = quark_uart_shutdown,
++ .set_termios = quark_uart_set_termios,
++/* .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,
++ .request_port = quark_uart_request_port,
++ .config_port = quark_uart_config_port,
++ .verify_port = quark_uart_verify_port,
++#ifdef CONFIG_CONSOLE_POLL
++ .poll_get_char = quark_uart_get_poll_char,
++ .poll_put_char = quark_uart_put_poll_char,
++#endif
++};
++
++#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
++
++static void quark_console_putchar(struct uart_port *port, int ch)
++{
++ struct x1000_port *priv =
++ container_of(port, struct x1000_port, port);
++
++ wait_for_xmitr(priv, UART_LSR_THRE);
++ serial_out(priv, QUARK_UART_THR, ch);
++}
++
++/*
++ * Print a string to the serial port trying not to disturb
++ * any possible real use of the port...
++ *
++ * The console_lock must be held when we get here.
++ */
++static void
++quark_console_write(struct console *co, const char *s, unsigned int count)
++{
++ struct x1000_port *priv;
++ unsigned long flags;
++ int priv_locked = 1;
++ int port_locked = 1;
++ u8 ier;
++
++ priv = quark_uart_ports[co->index];
++
++ touch_nmi_watchdog();
++
++ local_irq_save(flags);
++ 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 */
++ port_locked = 0;
++ } else if (oops_in_progress) {
++ priv_locked = spin_trylock(&priv->lock);
++ port_locked = spin_trylock(&priv->port.lock);
++ } else {
++ spin_lock(&priv->lock);
++ spin_lock(&priv->port.lock);
++ }
++
++ /*
++ * First save the IER then disable the interrupts
++ */
++ ier = serial_in(priv, UART_IER);
++
++ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT);
++
++ uart_console_write(&priv->port, s, count, quark_console_putchar);
++
++ /*
++ * Finally, wait for transmitter to become empty
++ * and restore the IER
++ */
++ wait_for_xmitr(priv, BOTH_EMPTY);
++ serial_out(priv, UART_IER, ier);
++
++ if (port_locked)
++ spin_unlock(&priv->port.lock);
++ if (priv_locked)
++ spin_unlock(&priv->lock);
++ local_irq_restore(flags);
++}
++
++static int __init quark_console_setup(struct console *co, char *options)
++{
++ struct uart_port *port;
++ int baud = default_baud;
++ int bits = 8;
++ int parity = 'n';
++ int flow = 'n';
++
++ /*
++ * Check whether an invalid uart number has been specified, and
++ * if so, search for the first available port that does have
++ * console support.
++ */
++ if (co->index >= QUARK_UART_NR)
++ co->index = 0;
++ port = &quark_uart_ports[co->index]->port;
++
++ if (!port || !port->membase)
++ return -ENODEV;
++
++ port->uartclk = quark_uart_get_uartclk();
++
++ if (options)
++ uart_parse_options(options, &baud, &parity, &bits, &flow);
++
++ 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,
++ .device = uart_console_device,
++ .setup = quark_console_setup,
++ .flags = CON_PRINTBUFFER | CON_ANYTIME,
++ .index = -1,
++ .data = &quark_uart_driver,
++};
++
++#define QUARK_CONSOLE (&quark_console)
++#else
++#define QUARK_CONSOLE NULL
++#endif /* CONFIG_SERIAL_QUARK_UART_CONSOLE */
++
++static struct uart_driver quark_uart_driver = {
++ .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 struct x1000_port *quark_uart_init_port(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct x1000_port *priv;
++ int ret, len;
++ 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",
++ 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;
++
++ rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
++ if (!rxbuf)
++ goto init_port_free_txbuf;
++
++ pci_set_master(pdev);
++
++ spin_lock_init(&priv->lock);
++
++ priv->mapbase = pci_resource_start(pdev, 0);
++ len = pci_resource_len(pdev, 0);
++ priv->membase = ioremap_nocache(priv->mapbase, len);
++ if(priv->membase == NULL){
++ ret = -ENODEV;
++ goto init_port_free_txbuf;
++ }
++
++ priv->pdev = pdev;
++ priv->tx_empty = 1;
++ priv->rxbuf.buf = rxbuf;
++ priv->rxbuf.size = PAGE_SIZE;
++ priv->fifo_size = QUARK_UART_FIFO_LEN;
++ priv->uartclk = quark_uart_get_uartclk();
++ priv->port_type = PORT_MAX_8250 + 1; /* BOD what does this do ? TBD*/
++ priv->port.dev = &pdev->dev;
++ priv->port.membase = priv->membase;
++ priv->port.mapbase = priv->mapbase;
++ priv->port.irq = pdev->irq;
++ priv->port.iotype = UPIO_MEM;
++ 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;
++
++ spin_lock_init(&priv->port.lock);
++ pci_set_drvdata(pdev, priv);
++ priv->trigger_level = 1;
++ priv->fcr = 0;
++
++ 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)
++ goto init_port_hal_free;
++
++#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
++ quark_uart_ports[board->line_no] = priv;
++#endif
++ ret = uart_add_one_port(&quark_uart_driver, &priv->port);
++
++ if (ret < 0)
++ 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
++
++ 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_txbuf:
++ kfree(priv);
++init_port_alloc_err:
++
++ return NULL;
++}
++
++static void quark_uart_exit_port(struct x1000_port *priv)
++{
++
++#ifdef CONFIG_DEBUG_FS
++ if (priv->debugfs)
++ debugfs_remove(priv->debugfs);
++#endif
++ free_irq(priv->port.irq, priv);
++ uart_remove_one_port(&quark_uart_driver, &priv->port);
++ pci_set_drvdata(priv->pdev, NULL);
++ free_page((unsigned long)priv->rxbuf.buf);
++}
++
++static void quark_uart_pci_remove(struct pci_dev *pdev)
++{
++ struct x1000_port *priv = pci_get_drvdata(pdev);
++
++ pci_disable_msi(pdev);
++
++#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
++ quark_uart_ports[priv->port.line] = NULL;
++#endif
++ quark_uart_exit_port(priv);
++ pci_disable_device(pdev);
++ kfree(priv);
++ return;
++}
++#ifdef CONFIG_PM
++static int quark_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
++{
++ struct x1000_port *priv = pci_get_drvdata(pdev);
++
++ uart_suspend_port(&quark_uart_driver, &priv->port);
++
++ pci_save_state(pdev);
++ pci_set_power_state(pdev, pci_choose_state(pdev, state));
++ return 0;
++}
++
++static int quark_uart_pci_resume(struct pci_dev *pdev)
++{
++ struct x1000_port *priv = pci_get_drvdata(pdev);
++ int ret;
++
++ pci_set_power_state(pdev, PCI_D0);
++ pci_restore_state(pdev);
++
++ ret = pci_enable_device(pdev);
++ if (ret) {
++ dev_err(&pdev->dev,
++ "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
++ return ret;
++ }
++
++ uart_resume_port(&quark_uart_driver, &priv->port);
++
++ return 0;
++}
++#else
++#define quark_uart_pci_suspend NULL
++#define quark_uart_pci_resume NULL
++#endif
++
++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)},
++ { 0 }
++};
++
++static int quark_uart_pci_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ int ret;
++ struct x1000_port *priv;
++
++ ret = pci_enable_device(pdev);
++ if (ret < 0)
++ goto probe_error;
++
++ priv = quark_uart_init_port(pdev, id);
++ if (!priv) {
++ ret = -EBUSY;
++ goto probe_disable_device;
++ }
++ pci_set_drvdata(pdev, priv);
++
++ return ret;
++
++probe_disable_device:
++ pci_disable_msi(pdev);
++ pci_disable_device(pdev);
++probe_error:
++ return ret;
++}
++
++static struct pci_driver quark_uart_pci_driver = {
++ .name = "quark_uart",
++ .id_table = quark_uart_pci_ids,
++ .probe = quark_uart_pci_probe,
++ .remove = quark_uart_pci_remove,
++ .suspend = quark_uart_pci_suspend,
++ .resume = quark_uart_pci_resume,
++};
++
++static int __init quark_uart_module_init(void)
++{
++ int ret;
++
++ /* register as UART driver */
++ ret = uart_register_driver(&quark_uart_driver);
++ if (ret < 0)
++ return ret;
++
++ /* register as PCI driver */
++ ret = pci_register_driver(&quark_uart_pci_driver);
++ if (ret < 0)
++ uart_unregister_driver(&quark_uart_driver);
++
++ return ret;
++}
++module_init(quark_uart_module_init);
++
++static void __exit quark_uart_module_exit(void)
++{
++ pci_unregister_driver(&quark_uart_pci_driver);
++ uart_unregister_driver(&quark_uart_driver);
++}
++module_exit(quark_uart_module_exit);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("Intel QUARK X1000 UART PCI Driver");
++module_param(default_baud, uint, S_IRUGO);
++MODULE_PARM_DESC(default_baud,
++ "Default BAUD for initial driver state and console (default 115200)");
+diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h
+index 10496bd..8dd64e9 100644
+--- a/include/linux/intel_mid_dma.h
++++ b/include/linux/intel_mid_dma.h
+@@ -26,8 +26,10 @@
+ #define __INTEL_MID_DMA_H__
+
+ #include <linux/dmaengine.h>
++#include <linux/interrupt.h>
+
+ #define DMA_PREP_CIRCULAR_LIST (1 << 10)
++#define MAX_CHAN 4
+
+ /*DMA mode configurations*/
+ enum intel_mid_dma_mode {
+@@ -73,4 +75,188 @@ struct intel_mid_dma_slave {
+ struct dma_slave_config dma_slave;
+ };
+
++/**
++ * struct intel_mid_dma_chan - internal mid representation of a DMA channel
++ * @chan: dma_chan strcture represetation for mid chan
++ * @ch_regs: MMIO register space pointer to channel register
++ * @dma_base: MMIO register space DMA engine base pointer
++ * @ch_id: DMA channel id
++ * @lock: channel spinlock
++ * @active_list: current active descriptors
++ * @queue: current queued up descriptors
++ * @free_list: current free descriptors
++ * @slave: dma slave struture
++ * @descs_allocated: total number of decsiptors allocated
++ * @dma: dma device struture pointer
++ * @busy: bool representing if ch is busy (active txn) or not
++ * @in_use: bool representing if ch is in use or not
++ * @raw_tfr: raw trf interrupt received
++ * @raw_block: raw block interrupt received
++ */
++struct intel_mid_dma_chan {
++ struct dma_chan chan;
++ void __iomem *ch_regs;
++ void __iomem *dma_base;
++ int ch_id;
++ spinlock_t lock;
++ struct list_head active_list;
++ struct list_head queue;
++ struct list_head free_list;
++ unsigned int descs_allocated;
++ struct middma_device *dma;
++ bool busy;
++ bool in_use;
++ u32 raw_tfr;
++ u32 raw_block;
++ struct intel_mid_dma_slave *mid_slave;
++};
++
++struct intel_mid_dma_desc {
++ void __iomem *block; /*ch ptr*/
++ struct list_head desc_node;
++ struct dma_async_tx_descriptor txd;
++ size_t len;
++ dma_addr_t sar;
++ dma_addr_t dar;
++ u32 cfg_hi;
++ u32 cfg_lo;
++ u32 ctl_lo;
++ u32 ctl_hi;
++ struct pci_pool *lli_pool;
++ struct intel_mid_dma_lli *lli;
++ dma_addr_t lli_phys;
++ unsigned int lli_length;
++ unsigned int current_lli;
++ dma_addr_t next;
++ enum dma_transfer_direction dirn;
++ enum dma_status status;
++ enum dma_slave_buswidth width; /*width of DMA txn*/
++ enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
++
++};
++
++
++enum intel_mid_dma_state {
++ RUNNING = 0,
++ SUSPENDED,
++};
++/**
++ * struct middma_device - internal representation of a DMA device
++ * @pdev: PCI device
++ * @dma_base: MMIO register space pointer of DMA
++ * @dma_pool: for allocating DMA descriptors
++ * @common: embedded struct dma_device
++ * @tasklet: dma tasklet for processing interrupts
++ * @ch: per channel data
++ * @pci_id: DMA device PCI ID
++ * @intr_mask: Interrupt mask to be used
++ * @mask_reg: MMIO register for periphral mask
++ * @chan_base: Base ch index (read from driver data)
++ * @max_chan: max number of chs supported (from drv_data)
++ * @block_size: Block size of DMA transfer supported (from drv_data)
++ * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
++ * @state: dma PM device state
++ */
++struct middma_device {
++ struct pci_dev *pdev;
++ void __iomem *dma_base;
++ struct pci_pool *dma_pool;
++ struct dma_device common;
++ struct tasklet_struct tasklet;
++ struct intel_mid_dma_chan ch[MAX_CHAN];
++ unsigned int pci_id;
++ unsigned int intr_mask;
++ void __iomem *mask_reg;
++ int chan_base;
++ int max_chan;
++ int block_size;
++ bool ispci_fn;
++ unsigned int pimr_mask;
++ enum intel_mid_dma_state state;
++};
++
++/**
++ * struct intel_mid_dma_probe_info
++ *
++ * @max_chan: maximum channels to probe
++ * @ch_base: offset from register base
++ * @block_size: TBD
++ * @pimr_mask: indicates if mask registers to be mapped
++ */
++struct intel_mid_dma_probe_info {
++ u8 max_chan;
++ u8 ch_base;
++ u16 block_size;
++ u32 pimr_mask;
++};
++
++
++/**
++ * intel_mid_dma_interrupt - DMA ISR
++ * @irq: IRQ where interrupt occurred
++ * @data: ISR cllback data (the controller structure)
++ *
++ * See if this is our interrupt if so then schedule the tasklet
++ * otherwise ignore
++ */
++irqreturn_t intel_mid_dma_interrupt(int irq, void *data);
++
++/**
++ * mid_setup_dma - Setup DMA controller
++ * @pdev: Controller PCI device structure
++ *
++ * Called by remove
++ * Unregister DMa controller, clear all structures and free interrupt
++ */
++int mid_setup_dma(struct pci_dev *pdev, struct middma_device *dma);
++
++/**
++ * middma_shutdown - Shutdown the DMA controller
++ * @pdev: Controller PCI device structure
++ *
++ * Called by remove
++ * Unregister DMa controller, clear all structures and free interrupt
++ */
++void middma_shutdown(struct pci_dev *pdev, struct middma_device *device);
++
++/**
++ * intel_mid_dma_probe - PCI Probe
++ * @pdev: Controller PCI device structure
++ * @id: pci device id structure
++ *
++ * Initialize the PCI device, map BARs, query driver data.
++ * Call intel_setup_dma to complete contoller and chan initilzation
++ */
++int intel_qrk_dma_probe(struct pci_dev *pdev,
++ struct middma_device *device);
++/**
++ * intel_mid_dma_remove - PCI remove
++ * @pdev: Controller PCI device structure
++ *
++ * Free up all resources and data
++ * Call shutdown_dma to complete contoller and chan cleanup
++ */
++void intel_qrk_dma_remove(struct pci_dev *pdev, struct middma_device *device);
++
++/* Power Management */
++/*
++* dma_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++int intel_qrk_dma_suspend(struct middma_device *device);
++
++/**
++* intel_qrk_dma_resume - PCI resume function
++*
++* @pci: PCI device structure
++*
++* This function is called by OS when a power event occurs
++*/
++int intel_qrk_dma_resume(struct middma_device *device);
++
++
+ #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
new file mode 100644
index 0000000..ff299ee
--- /dev/null
+++ b/recipes-kernel/linux/files/0009-EFI-capsule-update-quark.patch
@@ -0,0 +1,398 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <bryan.odonoghue@intel.com>
+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(-)
+ 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
+index 6db1cc4..03a4329 100644
+--- a/arch/x86/platform/efi/Makefile
++++ b/arch/x86/platform/efi/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
+-obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
++obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
++obj-$(CONFIG_EFI_CAPSULE) += efi_capsule_update.o
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index e2cd38f..0e22b5f4 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -847,6 +847,7 @@ void __init efi_enter_virtual_mode(void)
+ u64 end, systab, end_pfn;
+ void *p, *va, *new_memmap = NULL;
+ int count = 0;
++ bool bgrt_map;
+
+ efi.systab = NULL;
+
+@@ -860,6 +861,11 @@ void __init efi_enter_virtual_mode(void)
+ return;
+ }
+
++ /*
++ * Determine if mapping EFI boot code/data is required for BGRT mapping
++ */
++ bgrt_map = efi_bgrt_probe();
++
+ /* Merge contiguous regions of the same type and attribute */
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ u64 prev_size;
+@@ -889,9 +895,9 @@ void __init efi_enter_virtual_mode(void)
+
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+- if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+- md->type != EFI_BOOT_SERVICES_CODE &&
+- md->type != EFI_BOOT_SERVICES_DATA)
++ if (!((md->attribute & EFI_MEMORY_RUNTIME) || (bgrt_map &&
++ (md->type == EFI_BOOT_SERVICES_CODE ||
++ md->type == EFI_BOOT_SERVICES_DATA))))
+ continue;
+
+ 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
+--- /dev/null
++++ b/arch/x86/platform/efi/efi_capsule_update.c
+@@ -0,0 +1,331 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++#define DEBUG
++#include <asm/qrk.h>
++#include <linux/errno.h>
++#include <linux/firmware.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/efi.h>
++
++#define DRIVER_NAME "efi_capsule_update"
++#define PFX "efi-capsupdate: "
++#define MAX_PATH 256
++#define MAX_CHUNK PAGE_SIZE
++#define CSH_HDR_SIZE 0x400
++
++typedef struct {
++ u64 length;
++ union {
++ u64 data_block;
++ u64 continuation_pointer;
++ };
++} efi_blk_desc_t;
++
++static struct kobject * efi_capsule_kobj;
++static struct device *dev;
++static struct list_head sg_list;
++static char fpath[MAX_PATH];
++static bool path_set = false;
++static int csh_jump = CSH_HDR_SIZE; /* Quark EDK wants CSH jump */
++
++/**
++ * efi_capsule_trigger_update
++ *
++ * Trigger the EFI capsule update
++ */
++static int efi_capsule_trigger_update(void)
++{
++ const struct firmware *fw_entry;
++ int ret = 0;
++ u32 nblocks = 0, i = 0, total_size = 0, data_len = 0, offset = 0;
++ efi_capsule_header_t *chdr = NULL;
++ efi_blk_desc_t * desc_block = NULL;
++ u8 * data = NULL;
++
++ if (path_set == false)
++ return -ENODEV;
++
++ ret = request_firmware(&fw_entry, fpath, dev);
++ if (ret || fw_entry == NULL){
++ pr_err(PFX"unable to load firmware %s\n", fpath);
++ return ret;
++ }
++
++ /* Determine necessary sizes */
++ nblocks = (fw_entry->size/MAX_CHUNK) + 2;
++ total_size = fw_entry->size;
++
++ /* Allocate array of descriptor blocks + 1 for terminator */
++ desc_block = (efi_blk_desc_t*)kzalloc(nblocks * sizeof(efi_blk_desc_t), GFP_KERNEL);
++ if (desc_block == NULL){
++ pr_info(PFX"%s failed to allocate %d blocks\n", __func__, nblocks);
++ ret = -ENOMEM;
++ goto done_close;
++ }
++
++ pr_info(PFX"File %s size %u descriptor blocks %u\n",
++ fpath, total_size, nblocks);
++
++ /* Read in data */
++ for (i = 0; i < nblocks && offset < total_size; i++){
++ /* Determine read len */
++ data_len = offset < total_size - MAX_CHUNK ?
++ MAX_CHUNK : total_size - offset;
++ data = kmalloc(MAX_CHUNK, GFP_KERNEL);
++ if (data == NULL){
++ ret = -ENOMEM;
++ pr_info("Alloc fail %d bytes entry %d\n",
++ nblocks, i);
++ goto done;
++ }
++ memcpy(data, fw_entry->data + offset, data_len);
++ offset += data_len;
++
++ /* Sanity check */
++ if (i >= nblocks){
++ pr_err(PFX"%s Driver bug line %d\n", __func__, __LINE__);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ /* Validate header as appropriate */
++ if (chdr == NULL){
++ chdr = (efi_capsule_header_t*)&data[csh_jump];
++ desc_block[i].data_block = __pa(&data[csh_jump]);
++ desc_block[i].length = data_len - csh_jump;
++ pr_debug(PFX"hdr offset in file %d bytes\n", csh_jump);
++ pr_debug(PFX"hdr size %u flags 0x%08x imagesize 0x%08x\n",
++ chdr->headersize, chdr->flags, chdr->imagesize);
++
++ }else{
++ desc_block[i].data_block = __pa(data);
++ desc_block[i].length = data_len;
++ }
++ pr_debug(PFX "block %d length %u data @ phys 0x%08x virt %x\n",
++ i, (int)desc_block[i].length,
++ (unsigned int)desc_block[i].data_block, (unsigned int)data);
++ }
++
++ if (i > nblocks-1){
++ pr_err(PFX"%s Used block %d expected %d !\n", __func__, i, nblocks-1);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ pr_debug(PFX"submitting capsule to EDKII firmware\n");
++
++ ret = efi.update_capsule(&chdr, 1, __pa(desc_block));
++ if(ret != EFI_SUCCESS) {
++ pr_err(PFX"submission fail err=0x%08x\n", ret);
++ }else{
++ pr_debug(PFX"submission success\n");
++ ret = 0;
++ }
++
++ if (chdr != NULL && chdr->flags & 0x10000){
++ pr_debug(PFX"capsule persist across S3 skipping capsule free\n");
++ goto done_close;
++ }
++done:
++
++ for (i = 0; i < nblocks; i++){
++ if (desc_block[i].data_block != 0)
++ kfree(phys_to_virt((u32)desc_block[i].data_block));
++ }
++
++ if (desc_block != NULL)
++ kfree(desc_block);
++done_close:
++ release_firmware(fw_entry);
++ return ret;
++}
++
++/**
++ * efi_capsule_csh_jump
++ *
++ * sysfs callback used to show current path
++ */
++static ssize_t efi_capsule_csh_jump_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, sizeof(fpath), "%d\n", csh_jump > 0);
++}
++
++/**
++ * efi_capsule_path_store
++ *
++ * sysfs callback used to set a new capsule path
++ */
++static ssize_t efi_capsule_csh_jump_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (buf != NULL && buf[0] == '0')
++ csh_jump = 0;
++ else
++ csh_jump = CSH_HDR_SIZE;
++ return count;
++}
++
++static struct kobj_attribute efi_capsule_csh_jump_attr =
++ __ATTR(csh_jump, 0644, efi_capsule_csh_jump_show, efi_capsule_csh_jump_store);
++
++/**
++ * efi_capsule_path_show
++ *
++ * sysfs callback used to show current path
++ */
++static ssize_t efi_capsule_path_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, sizeof(fpath), fpath);
++}
++
++/**
++ * efi_capsule_path_store
++ *
++ * sysfs callback used to set a new capsule path
++ */
++static ssize_t efi_capsule_path_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (count > MAX_PATH-1)
++ return -EINVAL;
++
++ memset(fpath, 0x00, sizeof(fpath));
++ memcpy(fpath, buf, count);
++ path_set = true;
++
++ return count;
++}
++
++static struct kobj_attribute efi_capsule_path_attr =
++ __ATTR(capsule_path, 0644, efi_capsule_path_show, efi_capsule_path_store);
++
++/**
++ * efi_capsule_update_store
++ *
++ * sysfs callback used to initiate update
++ */
++static ssize_t efi_capsule_update_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{ int ret = 0;
++
++ ret = efi_capsule_trigger_update();
++ return ret == 0 ? count : ret;
++}
++
++static struct kobj_attribute efi_capsule_update_attr =
++ __ATTR(capsule_update, 0644, NULL, efi_capsule_update_store);
++
++static void efi_capsule_device_release(struct device *dev)
++{
++ kfree(dev);
++}
++
++#define SYSFS_ERRTXT "Error adding sysfs entry!\n"
++/**
++ * intel_qrk_capsule_update_init
++ *
++ * @return 0 success < 0 failure
++ *
++ * Module entry point
++ */
++static int __init efi_capsule_update_init(void)
++{
++ int retval = 0;
++ extern struct kobject * firmware_kobj;
++
++ INIT_LIST_HEAD(&sg_list);
++
++ /* efi_capsule_kobj subordinate of firmware @ /sys/firmware/efi */
++ efi_capsule_kobj = kobject_create_and_add("efi_capsule", firmware_kobj);
++ if (!efi_capsule_kobj) {
++ pr_err(PFX"kset create error\n");
++ retval = -ENODEV;
++ goto err;
++ }
++
++ dev = kzalloc(sizeof(struct device), GFP_KERNEL);
++ if (!dev) {
++ retval = -ENOMEM;
++ goto err_name;
++ }
++
++ retval = dev_set_name(dev, "%s", DRIVER_NAME);
++ if (retval < 0){
++ pr_err(PFX"dev_set_name err\n");
++ goto err_dev_reg;
++ }
++
++ dev->kobj.parent = efi_capsule_kobj;
++ dev->groups = NULL;
++ dev->release = efi_capsule_device_release;
++
++ retval = device_register(dev);
++ if (retval < 0){
++ pr_err(PFX"device_register error\n");
++ goto err_dev_reg;
++ }
++
++ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_path_attr.attr)) {
++ pr_err(PFX SYSFS_ERRTXT);
++ retval = -ENODEV;
++ goto err_dev_reg;
++ }
++ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_update_attr.attr)) {
++ pr_err(PFX SYSFS_ERRTXT);
++ retval = -ENODEV;
++ goto err_dev_reg;
++
++ }
++ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_csh_jump_attr.attr)) {
++ pr_err(PFX SYSFS_ERRTXT);
++ retval = -ENODEV;
++ goto err_dev_reg;
++
++ }
++ return 0;
++
++err_dev_reg:
++ put_device(dev);
++ dev = NULL;
++err_name:
++ kfree(dev);
++err:
++ return retval;
++}
++
++/**
++ * intel_qrk_esram_exit
++ *
++ * Module exit
++ */
++static void __exit efi_capsule_update_exit(void)
++{
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("EFI Capsule Update driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++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
new file mode 100644
index 0000000..990af2d
--- /dev/null
+++ b/recipes-kernel/linux/files/0010-Quark-SDIO-host-controller-quark.patch
@@ -0,0 +1,63 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Derek Browne <Derek.Browne@intel.com>
+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(-)
+
+diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
+index c7dd0cb..e5759b7 100644
+--- a/drivers/mmc/host/sdhci-pci.c
++++ b/drivers/mmc/host/sdhci-pci.c
+@@ -162,6 +162,10 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
+ };
+
++static const struct sdhci_pci_fixes sdhci_intel_qrk = {
++ .quirks = SDHCI_QUIRK_NO_HISPD_BIT,
++};
++
+ static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot)
+ {
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+@@ -777,6 +781,14 @@ static const struct pci_device_id pci_ids[] = {
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_QRK_SD,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_qrk,
++ },
++
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_MRST_SD0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
+index 0eb6579..b5bb350 100644
+--- a/include/linux/pci_ids.h
++++ b/include/linux/pci_ids.h
+@@ -2512,6 +2512,7 @@
+ #define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823
+ #define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824
+ #define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F
++#define PCI_DEVICE_ID_INTEL_QUARK_ILB 0x095E
+ #define PCI_DEVICE_ID_INTEL_I960 0x0960
+ #define PCI_DEVICE_ID_INTEL_I960RM 0x0962
+ #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60
+@@ -2534,6 +2535,7 @@
+ #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21
+ #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30
+ #define PCI_DEVICE_ID_INTEL_IOAT 0x1a38
++#define PCI_DEVICE_ID_INTEL_QRK_SD 0x08A7
+ #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
new file mode 100644
index 0000000..62a97a1
--- /dev/null
+++ b/recipes-kernel/linux/files/0011-Quark-USB-host-quark.patch
@@ -0,0 +1,95 @@
+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
+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(-)
+
+diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
+index 170b939..5eac9db 100644
+--- a/drivers/usb/host/ehci-pci.c
++++ b/drivers/usb/host/ehci-pci.c
+@@ -50,6 +50,10 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
+ if (!retval)
+ ehci_dbg(ehci, "MWI active\n");
+
++ /* Reset the threshold limit */
++ if(unlikely(usb_is_intel_qrk(pdev)))
++ usb_set_qrk_bulk_thresh(pdev);
++
+ return 0;
+ }
+
+diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
+index 4c338ec..c4c072a 100644
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -722,6 +722,48 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
+ return -ETIMEDOUT;
+ }
+
++#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939
++bool usb_is_intel_qrk(struct pci_dev *pdev)
++{
++ return pdev->vendor == PCI_VENDOR_ID_INTEL &&
++ pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
++
++}
++EXPORT_SYMBOL_GPL(usb_is_intel_qrk);
++
++#define EHCI_INSNREG01 0x84
++#define EHCI_INSNREG01_THRESH 0x007F007F /* Threshold value */
++void usb_set_qrk_bulk_thresh(struct pci_dev *pdev)
++{
++ void __iomem *base, *op_reg_base;
++ u8 cap_length;
++ u32 val;
++
++ if (!mmio_resource_enabled(pdev, 0))
++ return;
++
++ base = pci_ioremap_bar(pdev, 0);
++ if (base == NULL)
++ return;
++
++ cap_length = readb(base);
++ op_reg_base = base + cap_length;
++
++ val = readl(op_reg_base + EHCI_INSNREG01);
++ dev_printk(KERN_INFO, &pdev->dev, "INSNREG01 is 0x%08x\n", val);
++
++ val = EHCI_INSNREG01_THRESH;
++
++ writel(val, op_reg_base + EHCI_INSNREG01);
++
++ val = readl(op_reg_base + EHCI_INSNREG01);
++ dev_printk(KERN_INFO, &pdev->dev, "INSNREG01 is 0x%08x\n", val);
++
++ iounmap(base);
++
++}
++EXPORT_SYMBOL_GPL(usb_set_qrk_bulk_thresh);
++
+ #define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31
+ #define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31
+
+diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
+index 7f69a39..80ffdee 100644
+--- a/drivers/usb/host/pci-quirks.h
++++ b/drivers/usb/host/pci-quirks.h
+@@ -9,6 +9,8 @@ void usb_amd_dev_put(void);
+ void usb_amd_quirk_pll_disable(void);
+ void usb_amd_quirk_pll_enable(void);
+ bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
++bool usb_is_intel_qrk(struct pci_dev *pdev);
++void usb_set_qrk_bulk_thresh(struct pci_dev *pdev);
+ 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
new file mode 100644
index 0000000..2d7d88f
--- /dev/null
+++ b/recipes-kernel/linux/files/0012-USB-gadget-serial-quark.patch
@@ -0,0 +1,348 @@
+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
+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(-)
+
+diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf
+index f0ffc27..e56f074 100644
+--- a/Documentation/usb/linux-cdc-acm.inf
++++ b/Documentation/usb/linux-cdc-acm.inf
+@@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys
+ [SourceDisksFiles]
+ [SourceDisksNames]
+ [DeviceList]
+-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00
++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE
+
+ [DeviceList.NTamd64]
+-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00
++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE
+
+
+ ;------------------------------------------------------------------------------
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index 14625fd..1ab9996 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -439,7 +439,7 @@ config USB_GOKU
+ gadget drivers to also be dynamically linked.
+
+ config USB_EG20T
+- tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
++ tristate "Intel QRK/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
+ depends on PCI
+ help
+ This is a USB device driver for EG20T PCH.
+@@ -459,7 +459,8 @@ config USB_EG20T
+ ML7831 is for general purpose use.
+ ML7213/ML7831 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7831 is completely compatible for Intel EG20T PCH.
+-
++
++ This driver can be used with Intel's Quark SOC platform
+ #
+ # LAST -- dummy/emulated controller
+ #
+diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
+index 6490c00..df96b3b 100644
+--- a/drivers/usb/gadget/pch_udc.c
++++ b/drivers/usb/gadget/pch_udc.c
+@@ -6,6 +6,7 @@
+ * the Free Software Foundation; version 2 of the License.
+ */
+ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
++#include <asm/qrk.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/pci.h>
+@@ -18,6 +19,10 @@
+ #include <linux/gpio.h>
+ #include <linux/irq.h>
+
++static unsigned int enable_msi = 1;
++module_param(enable_msi, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
++
+ /* GPIO port for VBUS detecting */
+ static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
+
+@@ -343,6 +348,7 @@ struct pch_vbus_gpio_data {
+ * @setup_data: Received setup data
+ * @phys_addr: of device memory
+ * @base_addr: for mapped device memory
++ * @bar: Indicates which PCI BAR for USB regs
+ * @irq: IRQ line for the device
+ * @cfg_data: current cfg, intf, and alt in use
+ * @vbus_gpio: GPIO informaton for detecting VBUS
+@@ -371,13 +377,16 @@ struct pch_udc_dev {
+ struct usb_ctrlrequest setup_data;
+ unsigned long phys_addr;
+ void __iomem *base_addr;
++ unsigned bar;
+ unsigned irq;
+ struct pch_udc_cfg_data cfg_data;
+ struct pch_vbus_gpio_data vbus_gpio;
+ };
+
+-#define PCH_UDC_PCI_BAR 1
++#define PCH_UDC_PCI_BAR_QUARK 0
++#define PCH_UDC_PCI_BAR_EG20T 1
+ #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
++#define PCI_DEVICE_ID_INTEL_QUARK_UDC 0x0939
+ #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)
+ {
+ struct pch_udc_dev *dev = (struct pch_udc_dev *) pdev;
+ u32 dev_intr, ep_intr;
+- int i;
+-
+- dev_intr = pch_udc_read_device_interrupts(dev);
+- ep_intr = pch_udc_read_ep_interrupts(dev);
+-
+- /* For a hot plug, this find that the controller is hung up. */
+- if (dev_intr == ep_intr)
+- if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
+- dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
+- /* The controller is reset */
+- pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+- return IRQ_HANDLED;
++ int i, events = 0;
++
++ mask_pvm(dev->pdev);
++ do {
++ events = 0;
++ dev_intr = pch_udc_read_device_interrupts(dev);
++ ep_intr = pch_udc_read_ep_interrupts(dev);
++
++ /* For a hot plug, this find that the controller is hung up. */
++ if (dev_intr == ep_intr)
++ if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
++ dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
++ /* The controller is reset */
++ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
++ unmask_pvm(dev->pdev);
++ return IRQ_HANDLED;
++ }
++ if (dev_intr){
++ /* Clear device interrupts */
++ pch_udc_write_device_interrupts(dev, dev_intr);
++ events = 1;
+ }
+- if (dev_intr)
+- /* Clear device interrupts */
+- pch_udc_write_device_interrupts(dev, dev_intr);
+- if (ep_intr)
+- /* Clear ep interrupts */
+- pch_udc_write_ep_interrupts(dev, ep_intr);
+- if (!dev_intr && !ep_intr)
+- return IRQ_NONE;
+- spin_lock(&dev->lock);
+- if (dev_intr)
+- pch_udc_dev_isr(dev, dev_intr);
+- if (ep_intr) {
+- pch_udc_read_all_epstatus(dev, ep_intr);
+- /* Process Control In interrupts, if present */
+- if (ep_intr & UDC_EPINT_IN_EP0) {
+- pch_udc_svc_control_in(dev);
+- pch_udc_postsvc_epinters(dev, 0);
++ if (ep_intr){
++ /* Clear ep interrupts */
++ pch_udc_write_ep_interrupts(dev, ep_intr);
++ events = 1;
+ }
+- /* Process Control Out interrupts, if present */
+- if (ep_intr & UDC_EPINT_OUT_EP0)
+- pch_udc_svc_control_out(dev);
+- /* Process data in end point interrupts */
+- for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
+- if (ep_intr & (1 << i)) {
+- pch_udc_svc_data_in(dev, i);
+- pch_udc_postsvc_epinters(dev, i);
++ if (!dev_intr && !ep_intr){
++ unmask_pvm(dev->pdev);
++ return IRQ_NONE;
++ }
++ spin_lock(&dev->lock);
++ if (dev_intr){
++ pch_udc_dev_isr(dev, dev_intr);
++ }
++ if (ep_intr) {
++ pch_udc_read_all_epstatus(dev, ep_intr);
++ /* Process Control In interrupts, if present */
++ 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);
++ /* Process data in end point interrupts */
++ for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
++ if (ep_intr & (1 << i)) {
++ 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);
++ i++)
++ if (ep_intr & (1 << i))
++ pch_udc_svc_data_out(dev,
++ i - UDC_EPINT_OUT_SHIFT);
+ }
+- /* Process data out end point interrupts */
+- for (i = UDC_EPINT_OUT_SHIFT + 1; i < (UDC_EPINT_OUT_SHIFT +
+- PCH_UDC_USED_EP_NUM); i++)
+- if (ep_intr & (1 << i))
+- pch_udc_svc_data_out(dev, i -
+- UDC_EPINT_OUT_SHIFT);
+- }
+- spin_unlock(&dev->lock);
++ spin_unlock(&dev->lock);
++ }while(events == 1);
++ unmask_pvm(dev->pdev);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -3108,7 +3132,7 @@ static void pch_udc_remove(struct pci_dev *pdev)
+ iounmap(dev->base_addr);
+ if (dev->mem_region)
+ release_mem_region(dev->phys_addr,
+- pci_resource_len(pdev, PCH_UDC_PCI_BAR));
++ pci_resource_len(pdev, dev->bar));
+ if (dev->active)
+ pci_disable_device(pdev);
+ if (dev->registered)
+@@ -3184,9 +3208,16 @@ static int pch_udc_probe(struct pci_dev *pdev,
+ dev->active = 1;
+ pci_set_drvdata(pdev, dev);
+
++ /* Determine BAR based on PCI ID */
++ if(id->device == PCI_DEVICE_ID_INTEL_QUARK_UDC){
++ dev->bar = PCH_UDC_PCI_BAR_QUARK;
++ }else {
++ dev->bar = PCH_UDC_PCI_BAR_EG20T;
++ }
++
+ /* PCI resource allocation */
+- resource = pci_resource_start(pdev, 1);
+- len = pci_resource_len(pdev, 1);
++ resource = pci_resource_start(pdev, dev->bar);
++ len = pci_resource_len(pdev, dev->bar);
+
+ 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,
+ retval = -ENODEV;
+ goto finished;
+ }
++
++ pci_set_master(pdev);
++ if (enable_msi == 1){
++ pci_enable_msi(pdev);
++ }
++
+ 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,
+ dev->irq = pdev->irq;
+ dev->irq_registered = 1;
+
+- pci_set_master(pdev);
++
+ pci_try_set_mwi(pdev);
+
+ /* device struct setup */
+@@ -3261,6 +3298,11 @@ finished:
+
+ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
+ {
++ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QUARK_UDC),
++ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
++ .class_mask = 0xffffffff,
++ },
++ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class_mask = 0xffffffff,
+diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
+index 44752f5..e02a4c9 100644
+--- a/drivers/usb/gadget/serial.c
++++ b/drivers/usb/gadget/serial.c
+@@ -127,6 +127,15 @@ static unsigned n_ports = 1;
+ module_param(n_ports, uint, 0);
+ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
+
++static __u16 vendor = GS_VENDOR_ID;
++module_param(vendor, ushort, 0);
++MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
++ __MODULE_STRING(GS_VENDOR_ID)")");
++
++static __u16 product = 0;
++module_param(product, ushort, 0);
++MODULE_PARM_DESC(product, "User specified product ID");
++
+ /*-------------------------------------------------------------------------*/
+
+ static int __init serial_bind_config(struct usb_configuration *c)
+@@ -172,6 +181,14 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
+ status = strings_dev[STRING_DESCRIPTION_IDX].id;
+ serial_config_driver.iConfiguration = status;
+
++ /* Allow command line over-ride to set specific vendor/device id */
++ if (vendor != GS_VENDOR_ID)
++ device_desc.idVendor = cpu_to_le16(vendor);
++ if (product != 0)
++ device_desc.idProduct = cpu_to_le16(product);
++ pr_info("g_serial: Vendor 0x%04x Product 0x%04x\n",
++ device_desc.idVendor, device_desc.idProduct);
++
+ if (gadget_is_otg(cdev->gadget)) {
+ serial_config_driver.descriptors = otg_desc;
+ serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+@@ -201,6 +218,7 @@ static __refdata struct usb_composite_driver gserial_driver = {
+ .bind = gs_bind,
+ };
+
++static int bCfgVal;
+ static int __init init(void)
+ {
+ /* We *could* export two configs; that'd be much cleaner...
+@@ -208,19 +226,19 @@ static int __init init(void)
+ */
+ if (use_acm) {
+ serial_config_driver.label = "CDC ACM config";
+- serial_config_driver.bConfigurationValue = 2;
++ serial_config_driver.bConfigurationValue = ++bCfgVal;
+ device_desc.bDeviceClass = USB_CLASS_COMM;
+ device_desc.idProduct =
+ cpu_to_le16(GS_CDC_PRODUCT_ID);
+ } else if (use_obex) {
+ serial_config_driver.label = "CDC OBEX config";
+- serial_config_driver.bConfigurationValue = 3;
++ serial_config_driver.bConfigurationValue = ++bCfgVal;
+ device_desc.bDeviceClass = USB_CLASS_COMM;
+ device_desc.idProduct =
+ cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
+ } else {
+ serial_config_driver.label = "Generic Serial config";
+- serial_config_driver.bConfigurationValue = 1;
++ serial_config_driver.bConfigurationValue = ++bCfgVal;
+ 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
new file mode 100644
index 0000000..99ce791
--- /dev/null
+++ b/recipes-kernel/linux/files/0013-Quark-stmmac-Ethernet-quark.patch
@@ -0,0 +1,2219 @@
+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
+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(-)
+ 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
+index 1164930..c959209 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+@@ -26,8 +26,8 @@ config STMMAC_PLATFORM
+ If unsure, say N.
+
+ config STMMAC_PCI
+- bool "STMMAC PCI bus support (EXPERIMENTAL)"
+- depends on STMMAC_ETH && PCI && EXPERIMENTAL
++ bool "STMMAC PCI bus support"
++ depends on STMMAC_ETH && PCI
+ ---help---
+ This is to select the Synopsys DWMAC available on PCI devices,
+ if you have a controller with this interface, say Y or M here.
+@@ -54,6 +54,27 @@ config STMMAC_DA
+ By default, the DMA arbitration scheme is based on Round-robin
+ (rx:tx priority is 1:1).
+
++config STMMAC_PTP
++ bool "STMMAC PTP (1588-2005) Clock Support"
++ default n
++ depends on EXPERIMENTAL
++ select PPS
++ select PTP_1588_CLOCK
++ ---help---
++ Say Y here if you want support for 1588 Timestamping with a
++ Quark device, using the PTP 1588 Clock support. This is
++ required to enable timestamping support for the device.
++
++ If unsure, say N.
++
++config STMMAC_PTP_CLK_MHZ
++ depends on STMMAC_PTP
++ int "Reference clock in Mhz"
++ default 50
++ ---help---
++ Frequency if MHz of the reference clock used to derive PTP time
++ locally. Permissable values are 1 - 255 inclusive
++
+ choice
+ prompt "Select the DMA TX/RX descriptor operating modes"
+ depends on STMMAC_ETH
+diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
+index c8e8ea6..0995db5 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -3,6 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
+ stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
+ stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
+ stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
++stmmac-$(CONFIG_STMMAC_PTP) += stmmac_ptp.o
+ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
+ dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
+ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
+diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
+index 186d148..ad16e73 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -32,9 +32,15 @@
+ #include <linux/init.h>
+ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+ #define STMMAC_VLAN_TAG_USED
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++#define STMMAC_VLAN_HASH
++#endif
+ #include <linux/if_vlan.h>
+ #endif
+
++#if defined(STMMAC_VLAN_HASH) || defined(CONFIG_STMMAC_PTP)
++#define STMMAC_ATDS_USED
++#endif
+ #include "descs.h"
+ #include "mmc.h"
+
+@@ -319,15 +325,16 @@ struct stmmac_dma_ops {
+ void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
+ };
+
++struct stmmac_priv;
+ struct stmmac_ops {
+ /* MAC core initialization */
+ void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
+ /* Enable and verify that the IPC module is supported */
+- int (*rx_ipc) (void __iomem *ioaddr);
++ int (*set_rx_ipc) (void __iomem *ioaddr, bool on);
+ /* Dump MAC registers */
+ void (*dump_regs) (void __iomem *ioaddr);
+ /* Handle extra events on specific interrupts hw dependent */
+- int (*host_irq_status) (void __iomem *ioaddr);
++ int (*host_irq_status) (struct stmmac_priv * priv);
+ /* Multicast filter setting */
+ void (*set_filter) (struct net_device *dev, int id);
+ /* Flow control setting */
+@@ -340,6 +347,9 @@ struct stmmac_ops {
+ unsigned int reg_n);
+ void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n);
++ /* Enable/Disable VLAN Hash filters */
++ int (*vlan_rx_add_vid)(struct stmmac_priv *priv, unsigned short vid);
++ int (*vlan_rx_kill_vid)(struct stmmac_priv *priv, unsigned short vid);
+ void (*set_eee_mode) (void __iomem *ioaddr);
+ void (*reset_eee_mode) (void __iomem *ioaddr);
+ void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
+index 223adf9..ce08163 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
++++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
+@@ -25,8 +25,8 @@
+ #define __DESCS_H__
+
+ struct dma_desc {
+- /* Receive descriptor */
+ union {
++ /* Receive descriptor */
+ struct {
+ /* RDES0 */
+ u32 payload_csum_error:1;
+@@ -160,6 +160,49 @@ struct dma_desc {
+ } des01;
+ unsigned int des2;
+ unsigned int des3;
++
++ /* Enhanced mode - with VLAN/1588-2005/IPC CHKSUM offload */
++ #if defined(STMMAC_ATDS_USED)
++ union {
++ /* Receive descriptor */
++ struct {
++ /* RDES4 */
++ u32 ip_payload_type:3;
++ u32 ip_header_error:1;
++ u32 ip_payload_error:1;
++ u32 ip_checksum_bypassed:1;
++ u32 ipv4_packet_received:1;
++ u32 ipv6_packet_received:1;
++ u32 message_type:4;
++ u32 ptp_frame_type:1;
++ u32 ptp_version:1;
++ u32 timestamp_dropped:1;
++ u32 reserved1:1;
++ u32 av_packet_received:1;
++ u32 av_tagged_packet_received:1;
++ u32 vlan_tag_priority_value:3;
++ u32 reserved2:3;
++ u32 layer3_filter_match:1;
++ u32 layer4_filter_match:1;
++ u32 layer3_layer4_filter_num_matched:2;
++ u32 reserved3:4;
++
++ /* RDES5 */
++ u32 reserved4;
++ }erx;
++
++ /* Transmit descriptor */
++ struct {
++ /* TDES4 */
++ u32 reserved1;
++
++ /* TDES5 */
++ u32 reserved2;
++ } etx;
++ } des05;
++ unsigned int ts_lo; /* des6 Tx/Rx timestmp lo */
++ unsigned int ts_hi; /* des7 Tx/Rx timestamp hi */
++ #endif
+ };
+
+ /* Transmit checksum insertion control */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+index 7ad56af..3042098 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+@@ -50,7 +50,14 @@ enum dwmac1000_irq_status {
+ rgmii_irq = 0x0001,
+ };
+ #define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
+-
++#define GMAC_INT_MASK_LPIIM 0x00000200 /* LPI Interrupt Mask */
++#define GMAC_INT_MASK_TSIM 0x00000100 /* Timestamp Interrupt Mask */
++#define GMAC_INT_MASK_PMTIM 0x00000004 /* PMT Interrupt Mask */
++#define GMAC_INT_MASK_PCSANCIM 0x00000002 /* PCS AN Completion */
++#define GMAC_INT_MASK_PCSLCHGIM 0x00000001 /* PCS Link Status */
++#define GMAC_INT_MASK_DEFAULT GMAC_INT_MASK_PCSLCHGIM | GMAC_INT_MASK_PCSANCIM\
++ | GMAC_INT_MASK_PMTIM | GMAC_INT_MASK_TSIM\
++ | GMAC_INT_MASK_LPIIM
+ /* PMT Control and Status */
+ #define GMAC_PMT 0x0000002c
+ enum power_event {
+@@ -135,6 +142,7 @@ enum inter_frame_gap {
+ #define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
+ #define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
+ #define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
++#define GMAC_FRAME_FILTER_VTFE 0x00010000 /* VLAN Tag Filter Enable */
+ #define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
+ /* GMII ADDR defines */
+ #define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
+@@ -145,11 +153,17 @@ enum inter_frame_gap {
+ #define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
+ #define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
+ #define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
+-
++/* GMAC VLAN TAG defines */
++#define GMAC_VLAN_TAG_VTHM 0x00080000 /* Hash Table Match Enable */
++#define GMAC_VLAN_TAG_ESVL 0x00040000 /* Enable S-VLAN */
++#define GMAC_VLAN_TAG_VTIM 0x00020000 /* VLAN Tag inverse match */
++#define GMAC_VLAN_TAG_ETV 0x00010000 /* Enable 12-bit tag comp */
++#define GMAC_VLAN_TAG_VLMASK 0x0000FFFF /* VLAN tag ID for Rx frames */
+ /*--- DMA BLOCK defines ---*/
+ /* DMA Bus Mode register defines */
+ #define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
+ #define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
++#define DMA_BUS_MODE_ATDS 0X00000080 /* Alternate Descriptor Size */
+ #define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
+ #define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
+ /* Programmable burst length (passed thorugh platform)*/
+@@ -169,6 +183,7 @@ enum rx_tx_priority_ratio {
+ #define DMA_BUS_MODE_USP 0x00800000
+ #define DMA_BUS_MODE_PBL 0x01000000
+ #define DMA_BUS_MODE_AAL 0x02000000
++#define DMA_BUS_MODE_RIX 0x80000000
+
+ /* DMA CRS Control and Status Register Mapping */
+ #define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
+@@ -230,5 +245,50 @@ enum rtc_control {
+ #define GMAC_MMC_TX_INTR 0x108
+ #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
+
++/* VLAN Hash register offset */
++#define GMAC_VLAN_TAG_REP 0x584
++#define GMAC_VLAN_HASH 0x588
++#define GMAC_VLAN_HASH_MAXID 0x0F
++
++/***************** 1588 regs *****************/
++#define GMAC_TS_CTRL 0x700 /* Timestamp control reg */
++#define GMAC_TS_CTRL_TSENA 0x00000001 /* Timestamp enable */
++#define GMAC_TS_CTRL_TSCFUPDT 0x00000002 /* Timestamp fine/coarse */
++#define GMAC_TS_CTRL_TSINT 0x00000004 /* Timestamp initialise */
++#define GMAC_TS_CTRL_TSUPDT 0x00000008 /* Timestamp update */
++#define GMAC_TS_CTRL_TSTRIG 0x00000010 /* Timestamp trigger en */
++#define GMAC_TS_CTRL_TSADDREG 0x00000020 /* Timestamp addreg update */
++#define GMAC_TS_CTRL_TSENALL 0x00000100 /* Timestamp RX enable all */
++#define GMAC_TS_CTRL_TSCTRLSSR 0x00000200 /* Timestamp rollover ctr */
++#define GMAC_TS_CTRL_TSVER2ENA 0x00000400 /* Timestamp PTP v2 en */
++#define GMAC_TS_CTRL_TSIPENA 0x00000800 /* Timestamp PTP over eth */
++#define GMAC_TS_CTRL_TSIPV6ENA 0x00001000 /* Timestamp over IPV6 */
++#define GMAC_TS_CTRL_TSIPV4ENA 0x00002000 /* Timestamp over IPV4 */
++#define GMAC_TS_CTRL_TSEVNTENA 0x00004000 /* Timestamp event only */
++#define GMAC_TS_CTRL_TSMSTRENA 0x00008000 /* Timestamp master enable */
++#define GMAC_TS_CTRL_SNTYPSEL0 0x00000000 /* Timestamp type 0 snapshot */
++#define GMAC_TS_CTRL_SNTYPSEL1 0x00010000 /* Timestamp type 1 snapshot */
++#define GMAC_TS_CTRL_SNTYPSEL2 0x00020000 /* Timestamp type 2 snapshot */
++#define GMAC_TS_CTRL_SNTYPSEL3 0x00030000 /* Timestamp type 3 snapshot */
++#define GMAC_TS_CTRL_TSENMACADR 0x00040000 /* Timestamp mac filter en */
++#define GMAC_TS_CTRL_ATSFC 0x01000000 /* Timestamp aux fifo clear */
++#define GMAC_TS_CTRL_ATSEN0 0x02000000 /* Timestamp aux0 snap en */
++#define GMAC_TS_CTRL_ATSEN1 0x04000000 /* Timestamp aux1 snap en */
++#define GMAC_TS_CTRL_ATSEN2 0x08000000 /* Timestamp aux2 snap en */
++#define GMAC_TS_CTRL_ATSEN3 0x10000000 /* Timestamp aux3 enable */
++#define GMAC_SS_INC 0x704 /* Sub-second increment reg */
++#define GMAC_ST_SEC 0x708 /* System time seconds */
++#define GMAC_ST_NSEC 0x70C /* System time nseconds */
++#define GMAC_ST_SECUP 0x710 /* System time sec-update */
++#define GMAC_ST_NSECUP 0x714 /* System time nsec-update */
++#define GMAC_TS_APPEND 0x718 /* Timestamp append */
++#define GMAC_TT_SEC 0x71C /* Target time seconds */
++#define GMAC_TT_NSEC 0x720 /* Target time nseconds */
++#define GMAC_ST_HWSEC 0x724 /* System time high word sec */
++#define GMAC_ST_TS_STAT 0x728 /* Timestamp status */
++#define GMAC_PPS_CTRL 0x72C /* PPS signal output control */
++#define GMAC_AUXTS_NSEC 0x730 /* Aux timestamp counter nsec */
++#define GMAC_AUXTS_SEC 0x734 /* Aux timestamp counter sec */
++
+ extern const struct stmmac_dma_ops dwmac1000_dma_ops;
+ #endif /* __DWMAC1000_H__ */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+index bfe0226..b6d04ca 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+@@ -30,6 +30,7 @@
+ #include <linux/slab.h>
+ #include <asm/io.h>
+ #include "dwmac1000.h"
++#include "stmmac.h"
+
+ static void dwmac1000_core_init(void __iomem *ioaddr)
+ {
+@@ -38,7 +39,7 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ /* Mask GMAC interrupts */
+- writel(0x207, ioaddr + GMAC_INT_MASK);
++ writel(GMAC_INT_MASK_DEFAULT, ioaddr + GMAC_INT_MASK);
+
+ #ifdef STMMAC_VLAN_TAG_USED
+ /* Tag detection without filtering */
+@@ -46,11 +47,15 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
+ #endif
+ }
+
+-static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr)
++static int dwmac1000_set_rx_ipc(void __iomem *ioaddr, bool on)
+ {
+ u32 value = readl(ioaddr + GMAC_CONTROL);
+
+- value |= GMAC_CONTROL_IPC;
++ if(on == true){
++ value |= GMAC_CONTROL_IPC;
++ }else{
++ value &= ~GMAC_CONTROL_IPC;
++ }
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ value = readl(ioaddr + GMAC_CONTROL);
+@@ -87,6 +92,7 @@ static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+ static void dwmac1000_set_filter(struct net_device *dev, int id)
+ {
+ void __iomem *ioaddr = (void __iomem *) dev->base_addr;
++ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned int value = 0;
+ unsigned int perfect_addr_number;
+
+@@ -147,6 +153,10 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
+ /* Enable Receive all mode (to debug filtering_fail errors) */
+ value |= GMAC_FRAME_FILTER_RA;
+ #endif
++ if (priv->active_vlans != 0){
++ /* VLAN hash filtering is active on this interface */
++ value |= GMAC_FRAME_FILTER_VTFE;
++ }
+ writel(value, ioaddr + GMAC_FRAME_FILTER);
+
+ CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
+@@ -194,38 +204,42 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
+ }
+
+
+-static int dwmac1000_irq_status(void __iomem *ioaddr)
++#ifndef CONFIG_STMMAC_PTP
++#define stmmac_ptp_check_pps_event(x){}
++#endif
++
++static int dwmac1000_irq_status(struct stmmac_priv *priv)
+ {
+- u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
++ u32 intr_status = readl(priv->ioaddr + GMAC_INT_STATUS);
+ int status = 0;
+
+ /* Not used events (e.g. MMC interrupts) are not handled. */
+ if ((intr_status & mmc_tx_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
+- readl(ioaddr + GMAC_MMC_TX_INTR));
++ readl(priv->ioaddr + GMAC_MMC_TX_INTR));
+ status |= core_mmc_tx_irq;
+ }
+ if (unlikely(intr_status & mmc_rx_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
+- readl(ioaddr + GMAC_MMC_RX_INTR));
++ readl(priv->ioaddr + GMAC_MMC_RX_INTR));
+ status |= core_mmc_rx_irq;
+ }
+ if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
+- readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
++ readl(priv->ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+ status |= core_mmc_rx_csum_offload_irq;
+ }
+ if (unlikely(intr_status & pmt_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
+ /* clear the PMT bits 5 and 6 by reading the PMT
+ * status register. */
+- readl(ioaddr + GMAC_PMT);
++ readl(priv->ioaddr + GMAC_PMT);
+ status |= core_irq_receive_pmt_irq;
+ }
+ /* MAC trx/rx EEE LPI entry/exit interrupts */
+ if (intr_status & lpiis_irq) {
+ /* Clean LPI interrupt by reading the Reg 12 */
+- u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
++ u32 lpi_status = readl(priv->ioaddr + LPI_CTRL_STATUS);
+
+ if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
+ CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
+@@ -244,10 +258,110 @@ static int dwmac1000_irq_status(void __iomem *ioaddr)
+ status |= core_irq_rx_path_exit_lpi_mode;
+ }
+ }
++ if (unlikely(intr_status & time_stamp_irq)){
++ stmmac_ptp_check_pps_event(priv);
++ }
+
+ return status;
+ }
+
++static unsigned int dwmac1000_calc_vlan_4bit_crc ( const char * vlan )
++{
++ int i = 0, j = 0, len = 0, bit = 0;
++ unsigned int crc = 0xFFFFFFFF;
++ unsigned int poly = 0x04C11DB7;
++ unsigned char data;
++
++ if(unlikely(vlan == NULL)){
++ return 0;
++ }
++
++ for( i = 0; i < 2; i++ ) {
++ data = vlan[i];
++
++ if (i==0){
++ len = 8;
++ }else{
++ len = 4;
++ }
++
++ for( bit = 0; bit < len; bit++ ) {
++
++ j = ((crc >> 31) ^ data) & 0x1;
++ crc <<= 1;
++
++ if( j != 0 ){
++ crc ^= poly;
++ }
++
++ data >>= 1;
++ }
++ }
++ return crc;
++
++}
++
++static int dwmac1000_vlan_rx_add_vid(struct stmmac_priv *priv, unsigned short vid)
++{
++ u32 reg = 0;
++ u32 bit_nr = 0;
++
++ if(unlikely(priv == NULL || vid > GMAC_VLAN_HASH_MAXID)){
++ return -EINVAL;
++ }
++
++ if(priv->active_vlans == 0){
++
++ /* Flip the VTFE bit in GMAC_FRAME_FILTER */
++ reg = readl(priv->ioaddr + GMAC_FRAME_FILTER);
++ reg |= GMAC_FRAME_FILTER_VTFE;
++ writel(reg, priv->ioaddr + GMAC_FRAME_FILTER);
++
++ /* Enable hash filtering - based on 12 bit vid */
++ reg = readl(priv->ioaddr + GMAC_VLAN_TAG);
++ reg |= GMAC_VLAN_TAG_VTHM | GMAC_VLAN_TAG_ETV | 0x0000FFFF;
++ writel(reg, priv->ioaddr + GMAC_VLAN_TAG);
++ }
++
++ bit_nr = (~dwmac1000_calc_vlan_4bit_crc((const char*)&vid)) >> 28;
++ priv->active_vlans |= 1 << bit_nr;
++
++ writel(priv->active_vlans, priv->ioaddr + GMAC_VLAN_HASH);
++
++ return 0;
++}
++
++static int dwmac1000_vlan_rx_kill_vid(struct stmmac_priv *priv, unsigned short vid)
++{
++ u32 reg = 0;
++ u32 bit_nr = 0;
++
++ if(unlikely(priv == NULL || vid > GMAC_VLAN_HASH_MAXID)){
++ return -EINVAL;
++ }
++
++ bit_nr = (~dwmac1000_calc_vlan_4bit_crc((const char*)&vid)) >> 28;
++
++ priv->active_vlans &= ~(1 << bit_nr);
++ writel(priv->active_vlans, priv->ioaddr + GMAC_VLAN_HASH);
++
++ if(priv->active_vlans == 0){
++
++ /* Disable hash filtering */
++ reg = readl(priv->ioaddr + GMAC_VLAN_TAG);
++ reg &= ~(GMAC_VLAN_TAG_VTHM | GMAC_VLAN_TAG_ETV | 0x00000001);
++ writel(reg, priv->ioaddr + GMAC_VLAN_TAG);
++
++ /* Flip the VTFE bit in GMAC_FRAME_FILTER */
++ reg = readl(priv->ioaddr + GMAC_FRAME_FILTER);
++ reg &= ~GMAC_FRAME_FILTER_VTFE;
++ writel(reg, priv->ioaddr + GMAC_FRAME_FILTER);
++
++ }
++
++ return 0;
++}
++
+ static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
+ {
+ u32 value;
+@@ -297,9 +411,10 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
+ writel(value, ioaddr + LPI_TIMER_CTRL);
+ }
+
++
+ static const struct stmmac_ops dwmac1000_ops = {
+ .core_init = dwmac1000_core_init,
+- .rx_ipc = dwmac1000_rx_ipc_enable,
++ .set_rx_ipc = dwmac1000_set_rx_ipc,
+ .dump_regs = dwmac1000_dump_regs,
+ .host_irq_status = dwmac1000_irq_status,
+ .set_filter = dwmac1000_set_filter,
+@@ -307,6 +422,8 @@ static const struct stmmac_ops dwmac1000_ops = {
+ .pmt = dwmac1000_pmt,
+ .set_umac_addr = dwmac1000_set_umac_addr,
+ .get_umac_addr = dwmac1000_get_umac_addr,
++ .vlan_rx_add_vid = dwmac1000_vlan_rx_add_vid,
++ .vlan_rx_kill_vid = dwmac1000_vlan_rx_kill_vid,
+ .set_eee_mode = dwmac1000_set_eee_mode,
+ .reset_eee_mode = dwmac1000_reset_eee_mode,
+ .set_eee_timer = dwmac1000_set_eee_timer,
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+index bf83c03..a0c08e1 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+@@ -59,9 +59,12 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
+ * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
+ * depending on pbl value.
+ */
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ value = DMA_BUS_MODE_RIX | (pbl << DMA_BUS_MODE_PBL_SHIFT);
++#else
+ value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
+ (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+-
++#endif
+ /* Set the Fixed burst mode */
+ if (fb)
+ value |= DMA_BUS_MODE_FB;
+@@ -70,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
+ if (mb)
+ value |= DMA_BUS_MODE_MB;
+
++#if defined(STMMAC_ATDS_USED)
++ value |= DMA_BUS_MODE_ATDS;
++#endif
++
+ #ifdef CONFIG_STMMAC_DA
+ value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
+ #endif
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+index f83210e..43472c0 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+@@ -67,12 +67,12 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
+ readl(ioaddr + MAC_VLAN2));
+ }
+
+-static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
++static int dwmac100_set_rx_ipc(void __iomem *ioaddr, bool on)
+ {
+ return 0;
+ }
+
+-static int dwmac100_irq_status(void __iomem *ioaddr)
++static int dwmac100_irq_status(struct stmmac_priv *priv)
+ {
+ return 0;
+ }
+@@ -160,7 +160,7 @@ static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
+
+ static const struct stmmac_ops dwmac100_ops = {
+ .core_init = dwmac100_core_init,
+- .rx_ipc = dwmac100_rx_ipc_enable,
++ .set_rx_ipc = dwmac100_set_rx_ipc,
+ .dump_regs = dwmac100_dump_mac_regs,
+ .host_irq_status = dwmac100_irq_status,
+ .set_filter = dwmac100_set_filter,
+diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+index 0c74a70..50617c5 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+@@ -149,6 +149,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
+ {
+ writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
+ writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
++ writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);
+ }
+
+ /* This reads the MAC core counters (if actaully supported).
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+index b05df89..611f70e 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -27,9 +27,11 @@
+ #define DRV_MODULE_VERSION "Nov_2012"
+
+ #include <linux/clk.h>
++#include <linux/clocksource.h>
+ #include <linux/stmmac.h>
+ #include <linux/phy.h>
+ #include <linux/pci.h>
++#include <linux/ptp_clock_kernel.h>
+ #include "common.h"
+
+ struct stmmac_priv {
+@@ -72,8 +74,22 @@ struct stmmac_priv {
+ u32 msg_enable;
+ spinlock_t lock;
+ spinlock_t tx_lock;
++
++ /* PTP */
++ struct ptp_clock *ptp_clock;
++ struct ptp_clock_info ptp_caps;
++ struct delayed_work overflow_work;
++ spinlock_t tmreg_lock;
++ struct cyclecounter ccnt;
++ struct timecounter tcnt;
++// struct timecompare tcmp;
++ int hwts;
++ struct stmmac_timer *tm;
++
+ int wolopts;
+ int wol_irq;
++
++ int active_vlans;
+ struct plat_stmmacenet_data *plat;
+ struct stmmac_counters mmc;
+ struct dma_features dma_cap;
+@@ -81,6 +97,8 @@ struct stmmac_priv {
+ struct clk *stmmac_clk;
+ int clk_csr;
+ int synopsys_id;
++ int irqmode_msi;
++ struct pci_dev * pdev;
+ struct timer_list eee_ctrl_timer;
+ bool tx_path_in_lpi_mode;
+ int lpi_irq;
+@@ -110,6 +128,63 @@ int stmmac_dvr_remove(struct net_device *ndev);
+ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+ struct plat_stmmacenet_data *plat_dat,
+ void __iomem *addr);
++#ifdef CONFIG_STMMAC_PTP
++
++#define STMMAC_PTP_OVERFLOW_CHECK_ENABLED (u32)(1)
++#define STMMAC_PTP_PPS_ENABLED (u32)(1 << 1)
++#define STMMAC_PTP_HWTS_TX_EN (u32)(1 << 2)
++#define STMMAC_PTP_HWTS_RX_EN (u32)(1 << 3)
++
++extern void stmmac_ptp_init(struct net_device *ndev, struct device * pdev);
++extern void stmmac_ptp_remove(struct stmmac_priv *priv);
++extern int stmmac_ptp_hwtstamp_ioctl(struct stmmac_priv *priv,
++ struct ifreq *ifr, int cmd);
++extern void stmmac_ptp_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb);
++extern void stmmac_ptp_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb);
++extern void stmmac_ptp_check_pps_event(struct stmmac_priv *priv);
++#endif
++
++#ifdef CONFIG_HAVE_CLK
++static inline int stmmac_clk_enable(struct stmmac_priv *priv)
++{
++ if (!IS_ERR(priv->stmmac_clk))
++ return clk_prepare_enable(priv->stmmac_clk);
++
++ return 0;
++}
++
++static inline void stmmac_clk_disable(struct stmmac_priv *priv)
++{
++ if (IS_ERR(priv->stmmac_clk))
++ return;
++
++ clk_disable_unprepare(priv->stmmac_clk);
++}
++static inline int stmmac_clk_get(struct stmmac_priv *priv)
++{
++ priv->stmmac_clk = clk_get(priv->device, NULL);
++
++ if (IS_ERR(priv->stmmac_clk))
++ return PTR_ERR(priv->stmmac_clk);
++
++ return 0;
++}
++#else
++static inline int stmmac_clk_enable(struct stmmac_priv *priv)
++{
++ return 0;
++}
++static inline void stmmac_clk_disable(struct stmmac_priv *priv)
++{
++}
++static inline int stmmac_clk_get(struct stmmac_priv *priv)
++{
++ return 0;
++}
++#endif /* CONFIG_HAVE_CLK */
++
+ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
+ bool stmmac_eee_init(struct stmmac_priv *priv);
+
+@@ -167,6 +242,7 @@ static inline int stmmac_register_pci(void)
+ static inline void stmmac_unregister_pci(void)
+ {
+ }
++
+ #endif /* CONFIG_STMMAC_PCI */
+
+ #endif /* __STMMAC_H__ */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+index 1372ce2..0644dcd 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+@@ -31,6 +31,7 @@
+
+ #include "stmmac.h"
+ #include "dwmac_dma.h"
++#include "dwmac1000.h"
+
+ #define REG_SPACE_SIZE 0x1054
+ #define MAC100_ETHTOOL_NAME "st_mac100"
+@@ -231,9 +232,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
+ return -EBUSY;
+ }
+ cmd->transceiver = XCVR_INTERNAL;
+- spin_lock_irq(&priv->lock);
+ rc = phy_ethtool_gset(phy, cmd);
+- spin_unlock_irq(&priv->lock);
+ return rc;
+ }
+
+@@ -244,10 +243,7 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
+ struct phy_device *phy = priv->phydev;
+ int rc;
+
+- spin_lock(&priv->lock);
+ rc = phy_ethtool_sset(phy, cmd);
+- spin_unlock(&priv->lock);
+-
+ return rc;
+ }
+
+@@ -279,7 +275,7 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
+ static void stmmac_ethtool_gregs(struct net_device *dev,
+ struct ethtool_regs *regs, void *space)
+ {
+- int i;
++ int i, offset = 0;
+ u32 *reg_space = (u32 *) space;
+
+ struct stmmac_priv *priv = netdev_priv(dev);
+@@ -300,9 +296,20 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
+ /* MAC registers */
+ for (i = 0; i < 55; i++)
+ reg_space[i] = readl(priv->ioaddr + (i * 4));
++
++ /* VLAN registers */
++ offset = i;
++ reg_space[offset++] = readl(priv->ioaddr + GMAC_VLAN_TAG_REP);
++ reg_space[offset++] = readl(priv->ioaddr + GMAC_VLAN_HASH);
++
++ /* 1588 registers */
++ for(i = 0; i < 13; i++);
++ reg_space[i + offset] = readl(priv->ioaddr + (GMAC_TS_CTRL + (i * 4)));
++
+ /* DMA registers */
++ offset += i;
+ for (i = 0; i < 22; i++)
+- reg_space[i + 55] =
++ reg_space[i + offset] =
+ readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
+ }
+ }
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index b75f4b2..aaccd3a 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -28,6 +28,9 @@
+ https://bugzilla.stlinux.com/
+ *******************************************************************************/
+
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++#include <asm/qrk.h>
++#endif
+ #include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <linux/interrupt.h>
+@@ -135,6 +138,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+ #ifdef CONFIG_STMMAC_DEBUG_FS
+ static int stmmac_init_fs(struct net_device *dev);
+ static void stmmac_exit_fs(void);
++static int debugfs_registered = 0;
++
+ #endif
+
+ #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+@@ -502,13 +507,29 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
+ }
+
+ /**
++ * init_dma_err_cleanup
++ *
++ * @dev: net device to clean
++ * Description: Does a cleanup if kmalloc fails during init
++ */
++static void init_dma_err_cleanup(struct stmmac_priv * priv)
++{
++ if (priv->tx_skbuff != NULL)
++ kfree(priv->tx_skbuff);
++ if (priv->rx_skbuff_dma != NULL)
++ kfree (priv->rx_skbuff_dma);
++ if (priv->rx_skbuff != NULL)
++ kfree (priv->rx_skbuff);
++}
++
++/**
+ * init_dma_desc_rings - init the RX/TX descriptor rings
+ * @dev: net device structure
+ * Description: this function initializes the DMA RX/TX descriptors
+ * and allocates the socket buffers. It suppors the chained and ring
+ * modes.
+ */
+-static void init_dma_desc_rings(struct net_device *dev)
++static int init_dma_desc_rings(struct net_device *dev)
+ {
+ int i;
+ struct stmmac_priv *priv = netdev_priv(dev);
+@@ -532,8 +553,16 @@ static void init_dma_desc_rings(struct net_device *dev)
+ txsize, rxsize, bfsize);
+
+ priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
++ if (priv->rx_skbuff_dma == NULL)
++ return -ENOMEM;
++
+ priv->rx_skbuff =
+ kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
++ if (priv->rx_skbuff == NULL){
++ init_dma_err_cleanup(priv);
++ return -ENOMEM;
++ }
++
+ priv->dma_rx =
+ (struct dma_desc *)dma_alloc_coherent(priv->device,
+ rxsize *
+@@ -542,6 +571,11 @@ static void init_dma_desc_rings(struct net_device *dev)
+ GFP_KERNEL);
+ priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
+ GFP_KERNEL);
++ if (priv->tx_skbuff == NULL){
++ init_dma_err_cleanup(priv);
++ return -ENOMEM;
++ }
++
+ priv->dma_tx =
+ (struct dma_desc *)dma_alloc_coherent(priv->device,
+ txsize *
+@@ -550,8 +584,9 @@ static void init_dma_desc_rings(struct net_device *dev)
+ GFP_KERNEL);
+
+ if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) {
++ init_dma_err_cleanup(priv);
+ pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__);
+- return;
++ return -ENOMEM;
+ }
+
+ DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
+@@ -569,8 +604,9 @@ static void init_dma_desc_rings(struct net_device *dev)
+ skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
+ GFP_KERNEL);
+ if (unlikely(skb == NULL)) {
++ init_dma_err_cleanup(priv);
+ pr_err("%s: Rx init fails; skb is NULL\n", __func__);
+- break;
++ return -ENOMEM;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ priv->rx_skbuff[i] = skb;
+@@ -615,6 +651,8 @@ static void init_dma_desc_rings(struct net_device *dev)
+ pr_info("TX descriptor ring:\n");
+ display_ring(priv->dma_tx, txsize);
+ }
++
++ return 0;
+ }
+
+ static void dma_free_rx_skbufs(struct stmmac_priv *priv)
+@@ -736,6 +774,10 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
+ DMA_TO_DEVICE);
+ priv->hw->ring->clean_desc3(p);
+
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_tx_hwtstamp(priv, p, skb);
++#endif
++
+ if (likely(skb != NULL)) {
+ dev_kfree_skb(skb);
+ priv->tx_skbuff[entry] = NULL;
+@@ -963,6 +1005,25 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
+ }
+
+ /**
++ * stmmac_hw_set_rx_ipc
++ * @priv : pointer to the private device structure.
++ * Enables RX IPC offload if the feature is supported in hardware
++ */
++static int stmmac_hw_set_rx_ipc(struct stmmac_priv *priv, bool on)
++{
++ int ret = 0;
++
++ /* Enable the IPC (Checksum Offload) and check if the feature has been
++ * enabled during the core configuration. */
++ ret = priv->hw->mac->set_rx_ipc(priv->ioaddr, on);
++ if (on == true && !ret) {
++ pr_warning(" RX IPC Checksum Offload not configured.\n");
++ priv->plat->rx_coe = STMMAC_RX_COE_NONE;
++ }
++ return ret;
++}
++
++/**
+ * stmmac_tx_timer:
+ * @data: data pointer
+ * Description:
+@@ -1022,7 +1083,12 @@ static int stmmac_open(struct net_device *dev)
+ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
+ priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
+ priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
+- init_dma_desc_rings(dev);
++ ret = init_dma_desc_rings(dev);
++ if (ret < 0){
++ pr_err("%s: DMA initialization failed\n", __func__);
++ goto open_error;
++ }
++
+
+ /* DMA initialization and SW reset */
+ ret = stmmac_init_dma_engine(priv);
+@@ -1078,6 +1144,9 @@ static int stmmac_open(struct net_device *dev)
+ /* Set the HW DMA mode and the COE */
+ stmmac_dma_operation_mode(priv);
+
++ /* Enable RX IPC if supported by silicon */
++ ret = stmmac_hw_set_rx_ipc(priv, true);
++
+ /* Extra statistics */
+ memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
+ priv->xstats.threshold = tc;
+@@ -1085,9 +1154,12 @@ static int stmmac_open(struct net_device *dev)
+ stmmac_mmc_setup(priv);
+
+ #ifdef CONFIG_STMMAC_DEBUG_FS
+- ret = stmmac_init_fs(dev);
+- if (ret < 0)
+- pr_warning("%s: failed debugFS registration\n", __func__);
++ if (debugfs_registered == 0){
++ debugfs_registered = 1;
++ ret = stmmac_init_fs(dev);
++ if (ret < 0)
++ pr_warning("%s: failed debugFS registration\n", __func__);
++ }
+ #endif
+ /* Start the ball rolling... */
+ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
+@@ -1430,6 +1502,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
+ #endif
+ skb->protocol = eth_type_trans(skb, priv->dev);
+
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_tx_hwtstamp(priv, priv->dma_rx + entry, skb);
++#endif
+ if (unlikely(!priv->plat->rx_coe))
+ skb_checksum_none_assert(skb);
+ else
+@@ -1588,9 +1663,19 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
+ if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
+ features &= ~NETIF_F_ALL_CSUM;
+
++ stmmac_hw_set_rx_ipc(priv, features & NETIF_F_RXCSUM);
++
+ return features;
+ }
+
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define mask_pvm(x) qrk_pci_pvm_mask(x)
++ #define unmask_pvm(x) qrk_pci_pvm_unmask(x)
++#else
++ #define mask_pvm(x)
++ #define unmask_pvm(x)
++#endif
++
+ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+@@ -1601,10 +1686,12 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ return IRQ_NONE;
+ }
+
++ mask_pvm(priv->pdev);
++
+ /* To handle GMAC own interrupts */
+ if (priv->plat->has_gmac) {
+- int status = priv->hw->mac->host_irq_status((void __iomem *)
+- dev->base_addr);
++ int status = priv->hw->mac->host_irq_status(priv);
++
+ if (unlikely(status)) {
+ if (status & core_mmc_tx_irq)
+ priv->xstats.mmc_tx_irq_n++;
+@@ -1634,6 +1721,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ /* To handle DMA interrupts */
+ stmmac_dma_interrupt(priv);
+
++ unmask_pvm(priv->pdev);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -1669,7 +1758,15 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ if (!priv->phydev)
+ return -EINVAL;
+
+- ret = phy_mii_ioctl(priv->phydev, rq, cmd);
++ switch (cmd) {
++#ifdef CONFIG_STMMAC_PTP
++ case SIOCSHWTSTAMP:
++ ret = stmmac_ptp_hwtstamp_ioctl(priv, rq, cmd);
++ break;
++#endif
++ default:
++ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
++ }
+
+ return ret;
+ }
+@@ -1850,6 +1947,21 @@ static void stmmac_exit_fs(void)
+ }
+ #endif /* CONFIG_STMMAC_DEBUG_FS */
+
++#ifdef STMMAC_VLAN_HASH
++static int stmmac_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
++{
++ struct stmmac_priv *priv = netdev_priv(dev);
++ return priv->hw->mac->vlan_rx_add_vid(priv, vid);
++}
++
++static int stmmac_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
++{
++ struct stmmac_priv *priv = netdev_priv(dev);
++ return priv->hw->mac->vlan_rx_kill_vid(priv, vid);
++}
++
++#endif
++
+ static const struct net_device_ops stmmac_netdev_ops = {
+ .ndo_open = stmmac_open,
+ .ndo_start_xmit = stmmac_xmit,
+@@ -1860,6 +1972,10 @@ static const struct net_device_ops stmmac_netdev_ops = {
+ .ndo_tx_timeout = stmmac_tx_timeout,
+ .ndo_do_ioctl = stmmac_ioctl,
+ .ndo_set_config = stmmac_config,
++#ifdef STMMAC_VLAN_HASH
++ .ndo_vlan_rx_add_vid = stmmac_vlan_rx_add_vid,
++ .ndo_vlan_rx_kill_vid = stmmac_vlan_rx_kill_vid,
++#endif
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = stmmac_poll_controller,
+ #endif
+@@ -1924,13 +2040,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
+ /* Select the enhnaced/normal descriptor structures */
+ stmmac_selec_desc_mode(priv);
+
+- /* Enable the IPC (Checksum Offload) and check if the feature has been
+- * enabled during the core configuration. */
+- ret = priv->hw->mac->rx_ipc(priv->ioaddr);
+- if (!ret) {
+- pr_warning(" RX IPC Checksum Offload not configured.\n");
+- priv->plat->rx_coe = STMMAC_RX_COE_NONE;
+- }
++ ret = stmmac_hw_set_rx_ipc(priv, true);
+
+ if (priv->plat->rx_coe)
+ pr_info(" RX Checksum Offload Engine supported (type %d)\n",
+@@ -2001,6 +2111,12 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+ /* Both mac100 and gmac support receive VLAN tag detection */
+ ndev->features |= NETIF_F_HW_VLAN_RX;
+ #endif
++#ifdef STMMAC_VLAN_HASH
++ ndev->features |= NETIF_F_HW_VLAN_FILTER;
++ ndev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++ NETIF_F_RXCSUM;
++#endif
++
+ priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+ if (flow_ctrl)
+@@ -2044,6 +2160,10 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+ else
+ priv->clk_csr = priv->plat->clk_csr;
+
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_init(ndev, device);
++#endif
++
+ /* MDIO bus Registration */
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0) {
+@@ -2060,6 +2180,9 @@ error_clk_get:
+ unregister_netdev(ndev);
+ error_netdev_register:
+ netif_napi_del(&priv->napi);
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_remove(priv);
++#endif
+ free_netdev(ndev);
+
+ return NULL;
+@@ -2075,7 +2198,7 @@ int stmmac_dvr_remove(struct net_device *ndev)
+ {
+ struct stmmac_priv *priv = netdev_priv(ndev);
+
+- pr_info("%s:\n\tremoving driver", __func__);
++ pr_info("%s:\n\tremoving driver\n", __func__);
+
+ priv->hw->dma->stop_rx(priv->ioaddr);
+ priv->hw->dma->stop_tx(priv->ioaddr);
+@@ -2083,6 +2206,10 @@ int stmmac_dvr_remove(struct net_device *ndev)
+ stmmac_set_mac(priv->ioaddr, false);
+ stmmac_mdio_unregister(ndev);
+ netif_carrier_off(ndev);
++
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_remove(priv);
++#endif
+ unregister_netdev(ndev);
+ 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
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -23,32 +23,194 @@
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *******************************************************************************/
+
++#include <linux/dmi.h>
+ #include <linux/pci.h>
++#include <linux/platform_data/quark.h>
+ #include "stmmac.h"
+
+-struct plat_stmmacenet_data plat_dat;
+-struct stmmac_mdio_bus_data mdio_data;
+-struct stmmac_dma_cfg dma_cfg;
++/* List of supported PCI device IDs */
++#define STMMAC_VENDOR_ID 0x700
++#define STMMAC_DEVICE_ID 0x1108
++#define STMMAC_QUARK_ID 0x0937
++#define MAX_INTERFACES 0x02
++
++#if defined (CONFIG_INTEL_QUARK_X1000_SOC)
++static int enable_msi = 1;
++#else
++static int enable_msi = 0;
++#endif
++module_param(enable_msi, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
++
++static int bus_id = 1;
++static char stmmac_mac_data[MAX_INTERFACES][ETH_ALEN];
++
++struct stmmac_qrk_mac_data {
++ int phy_addr;
++ int bus_id;
++ const char * name;
++};
++
++static struct stmmac_qrk_mac_data phy_data [] = {
++ {
++ .phy_addr = -1, /* not connected */
++ .bus_id = 1,
++ .name = "QuarkEmulation",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .name = "QuarkEmulation",
++ },
++ {
++ .phy_addr = 3,
++ .bus_id = 1,
++ .name = "ClantonPeakSVP",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .name = "ClantonPeakSVP",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .name = "KipsBay",
++ },
++ {
++ .phy_addr = -1, /* not connected */
++ .bus_id = 2,
++ .name = "KipsBay",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .name = "CrossHill",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .name = "CrossHill",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .name = "ClantonHill",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .name = "ClantonHill",
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .name = "Galileo",
++ },
++ {
++ .phy_addr = -1, /* not connected */
++ .bus_id = 2,
++ .name = "Galileo",
++ },
++};
++
++
++static int stmmac_find_phy_addr(int mdio_bus_id)
++{
++ int i = 0;
++ const char * board_name = dmi_get_system_info(DMI_BOARD_NAME);
++ if (board_name == NULL)
++ return -1;
++
++ for (; i < sizeof(phy_data)/sizeof(struct stmmac_qrk_mac_data); i++){
++ if ((!strcmp(phy_data[i].name, board_name)) &&
++ phy_data[i].bus_id == mdio_bus_id)
++ return phy_data[i].phy_addr;
++ }
++
++ 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));
++
++ plat_dat->mdio_bus_data = kzalloc(sizeof(struct stmmac_mdio_bus_data),
++ GFP_KERNEL);
++ if (plat_dat->mdio_bus_data == NULL)
++ return -ENOMEM;
++
++ plat_dat->dma_cfg = kzalloc(sizeof(struct stmmac_dma_cfg),GFP_KERNEL);
++ if (plat_dat->dma_cfg == NULL)
++ return -ENOMEM;
++
++ if (id->device == STMMAC_QUARK_ID) {
++
++ phy_addr = stmmac_find_phy_addr(mdio_bus_id);
++ if (phy_addr == -1)
++ return -ENODEV;
++
++ plat_dat->bus_id = mdio_bus_id;
++ plat_dat->phy_addr = phy_addr;
++ plat_dat->interface = PHY_INTERFACE_MODE_RMII;
++ /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
++ plat_dat->clk_csr = 2;
++ plat_dat->has_gmac = 1;
++ plat_dat->force_sf_dma_mode = 1;
++
++ plat_dat->mdio_bus_data->phy_reset = NULL;
++ plat_dat->mdio_bus_data->phy_mask = 0;
++
++ plat_dat->dma_cfg->pbl = 16;
++ plat_dat->dma_cfg->fixed_burst = 1;
++ plat_dat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
++
++ } else {
++
++ plat_dat->bus_id = mdio_bus_id;
++ plat_dat->phy_addr = phy_addr;
++ plat_dat->interface = PHY_INTERFACE_MODE_GMII;
++ /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
++ plat_dat->clk_csr = 2;
++ plat_dat->has_gmac = 1;
++ plat_dat->force_sf_dma_mode = 1;
++
++ plat_dat->mdio_bus_data->phy_reset = NULL;
++ plat_dat->mdio_bus_data->phy_mask = 0;
++
++ plat_dat->dma_cfg->pbl = 32;
++ plat_dat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
++
++ }
++
++ return 0;
+ }
+
++#if 0
++/**
++ * stmmac_pci_find_mac
++ *
++ * @prive: pointer to private stmmac structure
++ * @mdio_bus_id : MDIO bus identifier used to find the platform MAC id
++ *
++ * Attempt to find MAC in platform data. If not found then driver will generate
++ * a random one for itself in any case
++ */
++void stmmac_pci_find_mac (struct stmmac_priv * priv, unsigned int mdio_bus_id)
++{
++ unsigned int id = mdio_bus_id - 1;
++ if (priv == NULL || id >= MAX_INTERFACES)
++ return;
++
++ if (intel_qrk_plat_get_mac(PLAT_DATA_MAC0+id,
++ (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,
+ int ret = 0;
+ void __iomem *addr = NULL;
+ struct stmmac_priv *priv = NULL;
++ struct plat_stmmacenet_data *plat_dat = NULL;
+ int i;
+
++ plat_dat = kmalloc(sizeof(struct plat_stmmacenet_data), GFP_KERNEL);
++ if (plat_dat == NULL){
++ ret = -ENOMEM;
++ goto err_out_map_failed;
++ }
++
++ /* return -ENODEV for non existing PHY, stop probing here */
++ ret = stmmac_default_data(plat_dat, bus_id, id);
++ if (ret != 0)
++ goto err_platdata;
++
++
+ /* Enable pci device */
+ ret = pci_enable_device(pdev);
+ if (ret) {
+@@ -96,30 +271,51 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
+ break;
+ }
+ pci_set_master(pdev);
++ if(enable_msi == 1){
++ pci_enable_msi(pdev);
++ pr_info("stmmac MSI mode enabled");
++ }
+
+- stmmac_default_data();
++ pr_info("Vendor 0x%04x Device 0x%04x\n",
++ id->vendor, id->device);
+
+- priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
++ priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
+ if (!priv) {
+ pr_err("%s: main driver probe failed", __func__);
+ goto err_out;
+ }
++#if 0
++ stmmac_pci_find_mac(priv, bus_id);
++#endif
+ priv->dev->irq = pdev->irq;
+ priv->wol_irq = pdev->irq;
+-
++ priv->irqmode_msi = enable_msi;
++ priv->pdev = pdev;
++ #ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ priv->lpi_irq = -ENXIO;
++ #endif
+ pci_set_drvdata(pdev, priv->dev);
+
+ pr_debug("STMMAC platform driver registration completed");
++ bus_id++;
+
+ return 0;
+
+ err_out:
+ pci_clear_master(pdev);
+-err_out_map_failed:
+ pci_release_regions(pdev);
+ err_out_req_reg_failed:
+ pci_disable_device(pdev);
+-
++err_platdata:
++ if (plat_dat != NULL){
++ if (plat_dat->dma_cfg != NULL)
++ kfree (plat_dat->dma_cfg);
++ if (plat_dat->mdio_bus_data != NULL)
++ kfree (plat_dat->mdio_bus_data);
++ kfree(plat_dat);
++ }
++err_out_map_failed:
++ bus_id++;
+ return ret;
+ }
+
+@@ -138,6 +334,21 @@ static void stmmac_pci_remove(struct pci_dev *pdev)
+ stmmac_dvr_remove(ndev);
+
+ pci_set_drvdata(pdev, NULL);
++
++ if(enable_msi == 1) {
++ if(pci_dev_msi_enabled(pdev)) {
++ pci_disable_msi(pdev);
++ }
++ }
++
++ if (priv->plat != NULL) {
++ if (priv->plat->dma_cfg != NULL)
++ kfree (priv->plat->dma_cfg);
++ if (priv->plat->mdio_bus_data != NULL)
++ kfree (priv->plat->mdio_bus_data);
++ kfree(priv->plat);
++ }
++
+ 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)
+ }
+ #endif
+
+-#define STMMAC_VENDOR_ID 0x700
+-#define STMMAC_DEVICE_ID 0x1108
+-
+ static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = {
+ {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
++ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, STMMAC_QUARK_ID)},
+ {}
+ };
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+new file mode 100644
+index 0000000..8552d0c
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+@@ -0,0 +1,723 @@
++/*******************************************************************************
++
++ STMMAC 1588-2005 hardware accel
++ Copyright(c) 2012 Intel Corporation. This code is based on IXGBE_PTP
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ more details.
++
++ You should have received a copy of the GNU General Public License along with
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
++ Contact Information::w
++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
++
++*******************************************************************************/
++#include "stmmac.h"
++#include "dwmac1000.h"
++#include <linux/export.h>
++#include <linux/net_tstamp.h>
++
++/* PPSCMD0 */
++#define STMMAC_PPSCMD_NONE 0x00 /* No command */
++#define STMMAC_PPSCMD_START_SINGLE 0x01 /* Start single pulse */
++#define STMMAC_PPSCMD_START_PULSE 0x02 /* Start pulse train */
++#define STMMAC_PPSCMD_START_CANCEL 0x03 /* Cancel start */
++#define STMMAC_PPSCMD_STOP_PULSE_ATTIME 0x04 /* Stop pulse train at time */
++#define STMMAC_PPSCMD_STOP_PULSE_IMMED 0x05 /* Stop pulse train immediate */
++#define STMMAC_PPSCMD_STOP_CANCEL 0x06 /* Stop cancel pulse train */
++
++#define STMMAC_PTP_OVERFLOW_CHECK_ENABLED (u32)(1)
++#define STMMAC_PTP_PPS_ENABLED (u32)(1 << 1)
++#define STMMAC_PTP_HWTS_TX_EN (u32)(1 << 2)
++#define STMMAC_PTP_HWTS_RX_EN (u32)(1 << 3)
++
++#ifndef NSECS_PER_SEC
++#define NSECS_PER_SEC 1000000000ULL
++#endif
++
++/*
++ * Structure of STMMAC timer registers
++ *
++ * GMAC_TS_HWSEC GMAC_ST_SEC GMAC_ST_NSEC
++ * +--------------+ +--------------+ +---+---+------+
++ * STMMAC | 16 | | 32 | | 32 |
++ * +--------------+ +--------------+ +---+---+------+
++ *
++ * The counter for the STMMAC is 80 bits
++ * - HWSEC == overflow value for ST_SEC => 130 years to overflow (optional)
++ * - ST_SEC == seconds
++ * - ST_NSEC == nanoseconds
++ */
++
++/**
++ * stmmac_ptp_read - read raw cycle counter (to be used by time counter)
++ * @cc - the cyclecounter structure
++ *
++ * this function reads the cyclecounter registers and is called by the
++ * cyclecounter structure used to construct a ns counter from the
++ * arbitrary fixed point registers
++ */
++static cycle_t stmmac_ptp_read(const struct cyclecounter *ccnt)
++{
++ struct stmmac_priv *priv =
++ container_of(ccnt, struct stmmac_priv, ccnt);
++ cycle_t stamp = 0;
++
++ stamp = (u64)readl(priv->ioaddr + GMAC_ST_NSEC);
++ stamp |= (u64)readl(priv->ioaddr + GMAC_ST_SEC) << 32;
++
++ return stamp;
++}
++
++/**
++ * stmmac_ptp_adjfreq
++ * @ptp - the ptp clock structure
++ * @ppb - parts per billion adjustment from base
++ *
++ * adjust the frequency of the ptp cycle counter by the
++ * indicated ppb from the base frequency.
++ */
++static int stmmac_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
++{
++ return 0;
++}
++
++/**
++ * stmmac_ptp_adjtime
++ * @ptp - the ptp clock structure
++ * @delta - offset to adjust the cycle counter by
++ *
++ * adjust the timer by resetting the timecounter structure.
++ */
++static int stmmac_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ unsigned long flags;
++ u64 now;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++
++ now = timecounter_read(&priv->tcnt);
++ now += delta;
++
++ /* reset the timecounter */
++ timecounter_init(&priv->tcnt,
++ &priv->ccnt,
++ now);
++
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++ return 0;
++}
++
++/**
++ * stmmac_ptp_gettime
++ * @ptp - the ptp clock structure
++ * @ts - timespec structure to hold the current time value
++ *
++ * read the timecounter and return the correct value on ns,
++ * after converting it into a struct timespec.
++ */
++static int stmmac_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ u64 ns;
++ u32 remainder;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ ns = timecounter_read(&priv->tcnt);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
++ ts->tv_nsec = remainder;
++
++ return 0;
++}
++
++/**
++ * stmmac_ptp_settime
++ * @ptp - the ptp clock structure
++ * @ts - the timespec containing the new time for the cycle counter
++ *
++ * reset the timecounter to use a new base value instead of the kernel
++ * wall timer value.
++ */
++static int stmmac_ptp_settime(struct ptp_clock_info *ptp,
++ const struct timespec *ts)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ u64 ns;
++ unsigned long flags;
++
++ ns = ts->tv_sec * 1000000000ULL;
++ ns += ts->tv_nsec;
++
++ /* reset the timecounter */
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ timecounter_init(&priv->tcnt, &priv->ccnt, ns);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ return 0;
++}
++
++/**
++ * stmmac_ptp_enable
++ * @ptp - the ptp clock structure
++ * @rq - the requested feature to change
++ * @on - whether to enable or disable the feature
++ *
++ * enable (or disable) ancillary features of the phc subsystem.
++ * our driver only supports the PPS feature on the X540
++ */
++static int stmmac_ptp_enable(struct ptp_clock_info *ptp,
++ struct ptp_clock_request *rq, int on)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ uint32_t reg = 0;
++
++ /**
++ * When enabling PPS functionality in STMMAC we need to unmask the
++ * interrupt mask reg and enable the TSTRIG bit in the timestamp control
++ * reg
++ */
++ if (rq->type == PTP_CLK_REQ_PPS) {
++ if (on){
++ priv->hwts |= STMMAC_PTP_PPS_ENABLED;
++
++ /* Enable TSTRIG */
++ reg = readl(priv->ioaddr + GMAC_TS_CTRL);
++ reg |= GMAC_TS_CTRL_TSTRIG;
++ writel(reg, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ /* Unmask interrupt */
++ reg = readl(priv->ioaddr + GMAC_INT_MASK);
++ printk(KERN_INFO "%s[on] read interrupt mask 0x%08x\n", __func__, reg);
++ reg &= ~GMAC_INT_MASK_TSIM;
++ printk(KERN_INFO "%s[on] write interrupt mask 0x%08x\n", __func__, reg);
++ writel(reg, priv->ioaddr + GMAC_INT_MASK);
++ wmb();
++
++ } else {
++ /* Mask interrupt */
++ reg = readl(priv->ioaddr + GMAC_INT_MASK);
++ printk(KERN_INFO "%s[off] read interrupt mask 0x%08x\n", __func__, reg);
++ reg |= GMAC_INT_MASK_TSIM;
++ printk(KERN_INFO "%s[off] write interrupt mask 0x%08x\n", __func__, reg);
++ writel(reg, priv->ioaddr + GMAC_INT_MASK);
++ wmb();
++
++ /* Disable TSTRIG */
++ reg = readl(priv->ioaddr + GMAC_TS_CTRL);
++ reg &= ~GMAC_TS_CTRL_TSTRIG;
++ writel(reg, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ priv->hwts &=
++ ~STMMAC_PTP_PPS_ENABLED;
++ }
++ return 0;
++ }
++
++ return -ENOTSUPP;
++}
++
++/**
++ * stmmac_ptp_check_pps_event
++ * @priv - the private priv structure
++ *
++ * This function is called by the interrupt routine when checking for
++ * interrupts. It will check and handle a pps event.
++ */
++void stmmac_ptp_check_pps_event(struct stmmac_priv *priv)
++{
++ struct ptp_clock_event event;
++ event.type = PTP_CLOCK_PPS;
++
++ /* Make sure ptp clock is valid, and PPS event enabled */
++ if (!priv->ptp_clock ||
++ !(priv->hwts & STMMAC_PTP_PPS_ENABLED)){
++ return;
++ }
++
++ ptp_clock_event(priv->ptp_clock, &event);
++}
++
++#if 0
++/**
++ * stmmac_ptp_overflow_check - delayed work to detect SYSTIME overflow
++ * @work: structure containing information about this work task
++ *
++ * this work function is scheduled to continue reading the timecounter
++ * in order to prevent missing when the system time registers wrap
++ * around. This needs to be run approximately twice a minute when no
++ * PTP activity is occurring.
++ */
++void stmmac_ptp_overflow_check(struct stmmac_priv *priv)
++{
++ unsigned long elapsed_jiffies = priv->last_overflow_check - jiffies;
++ struct timespec ts;
++
++ if ((priv->hwts & STMMAC_PTP_OVERFLOW_CHECK_ENABLED) &&
++ (elapsed_jiffies >= STMMAC_OVERFLOW_PERIOD)) {
++ stmmac_ptp_gettime(&priv->ptp_caps, &ts);
++ priv->last_overflow_check = jiffies;
++ }
++}
++#endif
++
++/**
++ * stmmac_ptp_tx_hwtstamp - utility function which checks for TX time stamp
++ * @q_vector: structure containing interrupt and ring information
++ * @skb: particular skb to send timestamp with
++ *
++ * if the timestamp is valid, we convert it into the timecounter ns
++ * value, then store that result into the shhwtstamps structure which
++ * is passed up the network stack
++ */
++void stmmac_ptp_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb)
++{
++ /* Sanity check input */
++ if (unlikely(priv == NULL || pdma == NULL || skb == NULL)){
++ return;
++ }
++
++ if(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP){
++ struct skb_shared_hwtstamps shhwtstamps;
++ u64 ns;
++ u64 regval;
++ unsigned long flags;
++
++ regval = (u64)pdma->ts_lo;
++ regval |= (u64)pdma->ts_hi << 32;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ ns = timecounter_cyc2time(&priv->tcnt, regval);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
++ shhwtstamps.hwtstamp = ns_to_ktime(ns);
++ skb_tstamp_tx(skb, &shhwtstamps);
++ }
++}
++
++/**
++ * stmmac_ptp_rx_hwtstamp - utility function which checks for RX time stamp
++ * @q_vector: structure containing interrupt and ring information
++ * @skb: particular skb to send timestamp with
++ *
++ * if the timestamp is valid, we convert it into the timecounter ns
++ * value, then store that result into the shhwtstamps structure which
++ * is passed up the network stack
++ */
++void stmmac_ptp_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb)
++{
++ /* Sanity check input */
++ if (unlikely(priv == NULL || pdma == NULL || skb == NULL)){
++ return;
++ }
++
++ if(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP){
++ struct skb_shared_hwtstamps shhwtstamps;
++ u64 ns;
++ u64 regval;
++ unsigned long flags;
++
++ regval = (u64)pdma->ts_lo;
++ regval |= (u64)pdma->ts_hi << 32;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ ns = timecounter_cyc2time(&priv->tcnt, regval);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
++ shhwtstamps.hwtstamp = ns_to_ktime(ns);
++ }
++}
++
++/**
++ * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping
++ * @priv: pointer to priv struct
++ * @ifreq: ioctl data
++ * @cmd: particular ioctl requested
++ *
++ * Outgoing time stamping can be enabled and disabled. Play nice and
++ * disable it when requested, although it shouldn't case any overhead
++ * when no packet needs it. At most one packet in the queue may be
++ * marked for time stamping, otherwise it would be impossible to tell
++ * for sure to which packet the hardware time stamp belongs.
++ *
++ * Incoming time stamping has to be configured via the hardware
++ * filters. Not all combinations are supported, in particular event
++ * type has to be specified. Matching the kind of event packet is
++ * not supported, with the exception of "all V2 events regardless of
++ * level 2 or 4".
++ */
++int stmmac_ptp_hwtstamp_ioctl(struct stmmac_priv *priv,
++ struct ifreq *ifr, int cmd)
++{
++ struct hwtstamp_config config;
++// struct stmmac_priv *priv = netdev_priv(netdev);
++ u32 tsctl = 0;
++
++ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
++ return -EFAULT;
++
++ /* reserved for future extensions */
++ if (config.flags)
++ return -EINVAL;
++
++ /* Snapshot the reg - preserve Timestamp Interrupt Trigger Enable */
++ tsctl = readl(priv->ioaddr + GMAC_TS_CTRL) & GMAC_TS_CTRL_TSTRIG;
++
++ /* TX */
++ switch (config.tx_type) {
++ case HWTSTAMP_TX_OFF:
++ priv->hwts &= ~STMMAC_PTP_HWTS_TX_EN;
++ printk(KERN_INFO "%s set TX PTP en false\n", __func__);
++ break;
++ case HWTSTAMP_TX_ON:
++ priv->hwts |= STMMAC_PTP_HWTS_TX_EN;
++ printk(KERN_INFO "%s set TX PTP en true\n", __func__);
++ break;
++ default:
++ return -ERANGE;
++ }
++
++ /* RX */
++ priv->hwts |= STMMAC_PTP_HWTS_RX_EN;
++
++ switch (config.rx_filter) {
++
++
++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
++ /*
++ * V1_L4 UDP any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=0, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
++ /*
++ * V1_L4 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=0, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
++ /*
++ * V1_L4 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=0, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSEVNTENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
++ /*
++ * V2_L4 UDP any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
++ /*
++ * V2_L4 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=1, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
++ /*
++ * V2_L4 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSEVNTENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
++ /*
++ * V2_L2 Ethernet any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1,TSIPENA=1
++ * TSIPENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSIPENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
++ /*
++ * V2_L2 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=1,TSIPENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
++ /*
++ * V2_L2 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1,
++ * TSIPENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_EVENT:
++ /*
++ * V2_L2 Ethernet any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1
++ * TSIPENA=1, TSIPV4ENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
++ /*
++ * V2_L2_L4 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1,
++ * TSVER2ENA=1,TSIPENA=1, TSIPV4ENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_SYNC:
++ /*
++ * V2_L2_L4 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1,
++ * TSIPENA=1, TSIPV4ENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_ALL:
++ /*
++ * V2_L2_L4 Ethernet any event
++ *
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * GMAC_TS_CTRL_TSENALL
++ */
++ tsctl |= GMAC_TS_CTRL_TSENALL;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_ALL \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_NONE:
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_NONE \n", __func__);
++ priv->hwts &= ~STMMAC_PTP_HWTS_RX_EN;
++ break;
++
++ default:
++ printk(KERN_INFO "%s error ioctl rx type %d \n", __func__, config.rx_filter);
++ /* bad/unknown parameter */
++ return -ERANGE;
++ }
++
++ /* Set the TS CTRL reg */
++ tsctl |= GMAC_TS_CTRL_TSENA;
++ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ printk(KERN_INFO "%s sync ts_ctl @ value 0x%08x\n", __func__, tsctl);
++
++ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
++ -EFAULT : 0;
++}
++
++
++#define DEFAULT_PTP_CLK 50
++
++/**
++ * stmmac_ptp_init_timestamp - initialise the PTP clock
++ * @priv - pointer to the priv structure
++ *
++ * This function initialises the PTP clock consistent with the method spelled
++ * out in the Snopsys documentation
++ */
++static void stmmac_ptp_init_timestamp(struct stmmac_priv *priv)
++{
++ unsigned long tsctl = GMAC_TS_CTRL_TSENA, flags = 0;
++ uint8_t ssinc = CONFIG_STMMAC_PTP_CLK_MHZ;
++
++ /* Enable TS */
++ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ /* Write SSINC - number of nano seconds to increment on each clock */
++ if(ssinc == 0){
++ ssinc = DEFAULT_PTP_CLK;
++ }
++ ssinc = 1000/ssinc;
++ writel(ssinc, priv->ioaddr + GMAC_SS_INC);
++ wmb();
++
++ printk(KERN_INFO "%s setting PTP_CLK to 0x%02x\n", __func__, ssinc);
++
++ /* Reset system time registers to zero */
++ writel(0x00000000, priv->ioaddr + GMAC_ST_SEC);
++ writel(0x00000000, priv->ioaddr + GMAC_ST_NSEC);
++ wmb();
++
++ /* Set TSINT to latch values in ST_SEC and ST_NSEC */
++ tsctl |= GMAC_TS_CTRL_TSINT;
++ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++ printk(KERN_INFO "%s tsctl == 0x%08lx (TSINIT | TSENA)\n", __func__, tsctl);
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++
++ /* Init timecounter */
++ memset(&priv->ccnt, 0, sizeof(priv->ccnt));
++ priv->ccnt.read = stmmac_ptp_read;
++ priv->ccnt.mask = CLOCKSOURCE_MASK(64);
++ priv->ccnt.mult = 1;
++ priv->ccnt.shift = 0;
++
++ /* reset the ns time counter */
++ timecounter_init(&priv->tcnt, &priv->ccnt,
++ ktime_to_ns(ktime_get_real()));
++
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++}
++
++/**
++ * stmmac_ptp_init
++ * @priv - the stmmac private priv structure
++ *
++ * This function performs the required steps for enabling ptp
++ * support. If ptp support has already been loaded it simply calls the
++ * cyclecounter init routine and exits.
++ */
++void stmmac_ptp_init(struct net_device *ndev, struct device * pdev)
++{
++ struct stmmac_priv *priv = netdev_priv(ndev);
++
++ /* Ensure the timestamp interrupt is masked */
++ writel(GMAC_INT_MASK_TSIM, priv->ioaddr + GMAC_INT_MASK);
++
++ /* Fill out PTP callback contents */
++ snprintf(priv->ptp_caps.name, 16, "%pm", ndev->dev_addr);
++ priv->ptp_caps.owner = THIS_MODULE;
++ priv->ptp_caps.max_adj = 0; /* Cannot be adjusted */
++ priv->ptp_caps.n_alarm = 0;
++ priv->ptp_caps.n_ext_ts = 0;
++ priv->ptp_caps.n_per_out = 0;
++ priv->ptp_caps.pps = 0;
++ priv->ptp_caps.adjfreq = stmmac_ptp_adjfreq;
++ priv->ptp_caps.adjtime = stmmac_ptp_adjtime;
++ priv->ptp_caps.gettime = stmmac_ptp_gettime;
++ priv->ptp_caps.settime = stmmac_ptp_settime;
++ priv->ptp_caps.enable = stmmac_ptp_enable;
++
++ spin_lock_init(&priv->tmreg_lock);
++
++ stmmac_ptp_init_timestamp(priv);
++
++ /* Init to default state */
++// priv->hwts = STMMAC_PTP_OVERFLOW_CHECK_ENABLED;
++
++ priv->ptp_clock = ptp_clock_register(&priv->ptp_caps, pdev);
++ if (IS_ERR(priv->ptp_clock)) {
++ priv->ptp_clock = NULL;
++ printk(KERN_ERR "%s ptp_clock_reg failed!\n", __func__);
++ } else {
++ printk(KERN_INFO "%s ptp_clock_reg success!\n", __func__);
++ }
++
++ return;
++}
++
++/**
++ * stmmac_ptp_remove - disable ptp device and stop the overflow check
++ * @priv: pointer to priv struct
++ *
++ * this function stops the ptp support, and cancels the delayed work.
++ */
++void stmmac_ptp_remove(struct stmmac_priv *priv)
++{
++ /* Ensure the timestamp interrupt is masked */
++ writel(GMAC_INT_MASK_TSIM, priv->ioaddr + GMAC_INT_MASK);
++
++ /* stop the overflow check task */
++// priv->hwts &= ~STMMAC_PTP_OVERFLOW_CHECK_ENABLED;
++
++ if (priv->ptp_clock != NULL) {
++ ptp_clock_unregister(priv->ptp_clock);
++ priv->ptp_clock = NULL;
++ printk(KERN_INFO "%s removed ptp_clock\n", __func__);
++ }
++}
++
+--
+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
new file mode 100644
index 0000000..9017515
--- /dev/null
+++ b/recipes-kernel/linux/files/0014-Quark-GPIO-2-2-quark.patch
@@ -0,0 +1,922 @@
+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
+Subject: [PATCH 14/21] Quark GPIO 2/2
+
+---
+ drivers/gpio/gpio-sch.c | 749 ++++++++++++++++++++++++++++++++++++++++-------
+ 1 files changed, 638 insertions(+), 111 deletions(-)
+
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index edae963..faabd97 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -28,6 +28,8 @@
+ #include <linux/pci_ids.h>
+
+ #include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
+
+ static DEFINE_SPINLOCK(gpio_lock);
+
+@@ -35,83 +37,168 @@ static DEFINE_SPINLOCK(gpio_lock);
+ #define CGIO (0x04)
+ #define CGLV (0x08)
+
++#define CGTPE (0x0C)
++#define CGTNE (0x10)
++#define CGGPE (0x14)
++#define CGSMI (0x18)
++#define CGTS (0x1C)
++
+ #define RGEN (0x20)
+ #define RGIO (0x24)
+ #define RGLV (0x28)
+
+-static unsigned short gpio_ba;
++#define RGTPE (0x2C)
++#define RGTNE (0x30)
++#define RGGPE (0x34)
++#define RGSMI (0x38)
++#define RGTS (0x3C)
+
+-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
++#define CGNMIEN (0x40)
++#define RGNMIEN (0x44)
++
++#define RESOURCE_IRQ 9
++
++static unsigned long gpio_ba;
++
++static int irq_num;
++
++struct sch_gpio_core_int_regvals {
++ u8 cgtpe;
++ u8 cgtne;
++ u8 cggpe;
++ u8 cgsmi;
++ u8 cgnmien;
++};
++
++struct sch_gpio_resume_int_regvals {
++ u8 rgtpe;
++ u8 rgtne;
++ u8 rggpe;
++ u8 rgsmi;
++ u8 rgnmien;
++};
++
++struct sch_gpio {
++ int irq_base_core;
++ struct sch_gpio_core_int_regvals initial_core;
++ struct sch_gpio_core_int_regvals lp_core;
++ int irq_base_resume;
++ struct sch_gpio_resume_int_regvals initial_resume;
++ struct sch_gpio_resume_int_regvals lp_resume;
++};
++
++static struct sch_gpio *chip_ptr;
++
++static void qrk_gpio_restrict_release(struct device *dev) {}
++static struct platform_device qrk_gpio_restrict_pdev = {
++ .name = "qrk-gpio-restrict-nc",
++ .dev.release = qrk_gpio_restrict_release,
++};
++
++static void sch_gpio_reg_clear_if_set(unsigned short reg,
++ unsigned short gpio_num)
+ {
+ u8 curr_dirs;
+ unsigned short offset, bit;
+
+- spin_lock(&gpio_lock);
+-
+- offset = CGIO + gpio_num / 8;
++ offset = reg + gpio_num / 8;
+ bit = gpio_num % 8;
+
+ curr_dirs = inb(gpio_ba + offset);
+
+- if (!(curr_dirs & (1 << bit)))
+- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+-
+- spin_unlock(&gpio_lock);
+- return 0;
++ if (curr_dirs & (1 << bit))
++ outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ }
+
+-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
++static void sch_gpio_reg_set_if_clear(unsigned short reg,
++ unsigned short gpio_num)
+ {
+- int res;
++ u8 curr_dirs;
+ unsigned short offset, bit;
+
+- offset = CGLV + gpio_num / 8;
++ offset = reg + gpio_num / 8;
+ bit = gpio_num % 8;
+
+- res = !!(inb(gpio_ba + offset) & (1 << bit));
+- return res;
++ curr_dirs = inb(gpio_ba + offset);
++
++ if (!(curr_dirs & (1 << bit)))
++ outb(curr_dirs | (1 << bit), gpio_ba + offset);
+ }
+
+-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
++static void sch_gpio_reg_set(unsigned short reg, unsigned short gpio_num,
++ int val)
+ {
+- u8 curr_vals;
++ u8 curr_dirs;
+ unsigned short offset, bit;
+
+- spin_lock(&gpio_lock);
+-
+- offset = CGLV + gpio_num / 8;
++ offset = reg + gpio_num / 8;
+ bit = gpio_num % 8;
+
+- curr_vals = inb(gpio_ba + offset);
++ curr_dirs = inb(gpio_ba + offset);
+
+ if (val)
+- outb(curr_vals | (1 << bit), gpio_ba + offset);
++ outb(curr_dirs | (1 << bit), gpio_ba + offset);
+ else
+- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+- spin_unlock(&gpio_lock);
++ outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ }
+
+-static int sch_gpio_core_direction_out(struct gpio_chip *gc,
+- unsigned gpio_num, int val)
++static unsigned short sch_gpio_reg_get(unsigned short reg,
++ unsigned short gpio_num)
+ {
+ u8 curr_dirs;
+ unsigned short offset, bit;
+
+- sch_gpio_core_set(gc, gpio_num, val);
++ offset = reg + gpio_num / 8;
++ bit = gpio_num % 8;
+
+- spin_lock(&gpio_lock);
++ curr_dirs = !!(inb(gpio_ba + offset) & (1 << bit));
+
+- offset = CGIO + gpio_num / 8;
+- bit = gpio_num % 8;
++ return curr_dirs;
++}
+
+- curr_dirs = inb(gpio_ba + offset);
+- if (curr_dirs & (1 << bit))
+- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
++static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++ sch_gpio_reg_set_if_clear(CGIO, gpio_num);
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++ return 0;
++}
++
++static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
++{
++ int res;
++ res = sch_gpio_reg_get(CGLV, gpio_num);
++
++ return res;
++}
++
++static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++ sch_gpio_reg_set(CGLV, gpio_num, val);
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++}
++
++static int sch_gpio_core_direction_out(struct gpio_chip *gc,
++ unsigned gpio_num, int val)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++ sch_gpio_reg_clear_if_set(CGIO, gpio_num);
++ spin_unlock_irqrestore(&gpio_lock, flags);
+
+- spin_unlock(&gpio_lock);
+ return 0;
+ }
+
++static int sch_gpio_core_to_irq(struct gpio_chip *gc, unsigned offset)
++{
++ return chip_ptr->irq_base_core + offset;
++}
++
+ 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 = {
+ .get = sch_gpio_core_get,
+ .direction_output = sch_gpio_core_direction_out,
+ .set = sch_gpio_core_set,
++ .to_irq = sch_gpio_core_to_irq,
+ };
+
+-static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
+- unsigned gpio_num)
++static void sch_gpio_core_irq_enable(struct irq_data *d)
+ {
+- 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);
++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);
++ gpio_num = d->irq - chip_ptr->irq_base_core;
++ sch_gpio_reg_clear_if_set(CGGPE, gpio_num);
++}
+
+- spin_unlock(&gpio_lock);
+- return 0;
++static void sch_gpio_core_irq_ack(struct irq_data *d)
++{
++ u32 gpio_num = 0;
++
++ gpio_num = d->irq - chip_ptr->irq_base_core;
++ sch_gpio_reg_set(CGTS, gpio_num, 1);
+ }
+
+-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
++static int sch_gpio_core_irq_type(struct irq_data *d, unsigned type)
+ {
+- return !!(inb(gpio_ba + RGLV) & (1 << gpio_num));
++ int ret = 0;
++ unsigned long flags = 0;
++ u32 gpio_num = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return -EFAULT;
++ }
++
++ gpio_num = d->irq - chip_ptr->irq_base_core;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ sch_gpio_reg_clear_if_set(CGTNE, gpio_num);
++ sch_gpio_reg_set_if_clear(CGTPE, gpio_num);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ sch_gpio_reg_clear_if_set(CGTPE, gpio_num);
++ sch_gpio_reg_set_if_clear(CGTNE, gpio_num);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ sch_gpio_reg_set_if_clear(CGTPE, gpio_num);
++ sch_gpio_reg_set_if_clear(CGTNE, gpio_num);
++ break;
++ case IRQ_TYPE_NONE:
++ sch_gpio_reg_clear_if_set(CGTPE, gpio_num);
++ sch_gpio_reg_clear_if_set(CGTNE, gpio_num);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++ return ret;
++}
++
++static struct irq_chip sch_irq_core = {
++ .irq_ack = sch_gpio_core_irq_ack,
++ .irq_set_type = sch_gpio_core_irq_type,
++ .irq_enable = sch_gpio_core_irq_enable,
++ .irq_disable = sch_gpio_core_irq_disable,
++};
++
++static void sch_gpio_core_irqs_init(struct sch_gpio *chip, unsigned int num)
++{
++ int i;
++
++ for (i = 0; i < num; i++) {
++ irq_set_chip_data(i + chip->irq_base_core, chip);
++ irq_set_chip_and_handler_name(i + chip->irq_base_core,
++ &sch_irq_core,
++ handle_simple_irq,
++ "sch_gpio_irq_core");
++ }
+ }
+
+-static void sch_gpio_resume_set(struct gpio_chip *gc,
+- unsigned gpio_num, int val)
++static void sch_gpio_core_irqs_deinit(struct sch_gpio *chip, unsigned int num)
+ {
+- u8 curr_vals;
++ int i;
+
+- spin_lock(&gpio_lock);
++ 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,
++ 0, 0, 0);
++ }
++}
+
+- curr_vals = inb(gpio_ba + RGLV);
++static void sch_gpio_core_irq_disable_all(struct sch_gpio *chip,
++ unsigned int num)
++{
++ unsigned long flags = 0;
++ u32 gpio_num = 0;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ for (gpio_num = 0; gpio_num < num; gpio_num++) {
++ sch_gpio_reg_clear_if_set(CGTPE, gpio_num);
++ sch_gpio_reg_clear_if_set(CGTNE, gpio_num);
++ sch_gpio_reg_clear_if_set(CGGPE, gpio_num);
++ sch_gpio_reg_clear_if_set(CGSMI, gpio_num);
++ sch_gpio_reg_clear_if_set(CGNMIEN, gpio_num);
++ /* 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);
+ }
+
+-static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
+- unsigned gpio_num, int val)
++void sch_gpio_core_save_state(struct sch_gpio_core_int_regvals *regs)
+ {
+- u8 curr_dirs;
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ regs->cgtpe = inb(gpio_ba + CGTPE);
++ regs->cgtne = inb(gpio_ba + CGTNE);
++ regs->cggpe = inb(gpio_ba + CGGPE);
++ regs->cgsmi = inb(gpio_ba + CGSMI);
++ regs->cgnmien = inb(gpio_ba + CGNMIEN);
+
+- 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);
++ 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);
++ spin_unlock_irqrestore(&gpio_lock, flags);
++}
++
++static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
++ unsigned gpio_num)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++ sch_gpio_reg_set_if_clear(RGIO, gpio_num);
++ spin_unlock_irqrestore(&gpio_lock, flags);
+ return 0;
+ }
+
++static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
++{
++ int res;
++ res = sch_gpio_reg_get(RGLV, gpio_num);
++ return res;
++}
++
++static void sch_gpio_resume_set(struct gpio_chip *gc, unsigned gpio_num,
++ int val)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++ sch_gpio_reg_set(RGLV, gpio_num, val);
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++}
++
++static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
++ unsigned gpio_num, int val)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++ sch_gpio_reg_clear_if_set(RGIO, gpio_num);
++ spin_unlock_irqrestore(&gpio_lock, flags);
++ return 0;
++}
++
++static int sch_gpio_resume_to_irq(struct gpio_chip *gc, unsigned offset)
++{
++ return chip_ptr->irq_base_resume + offset;
++}
++
+ 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 = {
+ .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;
++
++ gpio_num = d->irq - chip_ptr->irq_base_resume;
++ sch_gpio_reg_set_if_clear(RGGPE, gpio_num);
++}
++
++static void sch_gpio_resume_irq_disable(struct irq_data *d)
++{
++ u32 gpio_num = 0;
++
++ gpio_num = d->irq - chip_ptr->irq_base_resume;
++ sch_gpio_reg_clear_if_set(RGGPE, gpio_num);
++}
++
++static void sch_gpio_resume_irq_ack(struct irq_data *d)
++{
++ u32 gpio_num = 0;
++
++ gpio_num = d->irq - chip_ptr->irq_base_resume;
++ sch_gpio_reg_set(RGTS, gpio_num, 1);
++}
++
++static int sch_gpio_resume_irq_type(struct irq_data *d, unsigned type)
++{
++ int ret = 0;
++ unsigned long flags = 0;
++ u32 gpio_num = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return -EFAULT;
++ }
++
++ gpio_num = d->irq - chip_ptr->irq_base_resume;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ sch_gpio_reg_clear_if_set(RGTNE, gpio_num);
++ sch_gpio_reg_set_if_clear(RGTPE, gpio_num);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ sch_gpio_reg_clear_if_set(RGTPE, gpio_num);
++ sch_gpio_reg_set_if_clear(RGTNE, gpio_num);
++ break;
++ case IRQ_TYPE_EDGE_BOTH:
++ sch_gpio_reg_set_if_clear(RGTPE, gpio_num);
++ sch_gpio_reg_set_if_clear(RGTNE, gpio_num);
++ break;
++ case IRQ_TYPE_NONE:
++ sch_gpio_reg_clear_if_set(RGTPE, gpio_num);
++ sch_gpio_reg_clear_if_set(RGTNE, gpio_num);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++ return ret;
++}
++
++static struct irq_chip sch_irq_resume = {
++ .irq_ack = sch_gpio_resume_irq_ack,
++ .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;
++
++ for (i = 0; i < num; i++) {
++ irq_set_chip_data(i + chip->irq_base_resume, chip);
++ irq_set_chip_and_handler_name(i + chip->irq_base_resume,
++ &sch_irq_resume,
++ handle_simple_irq,
++ "sch_gpio_irq_resume");
++ }
++}
++
++static void sch_gpio_resume_irqs_deinit(struct sch_gpio *chip, unsigned int num)
++{
++ int i;
++
++ 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,
++ 0, 0, 0);
++ }
++}
++
++static void sch_gpio_resume_irq_disable_all(struct sch_gpio *chip,
++ unsigned int num)
++{
++ unsigned long flags = 0;
++ u32 gpio_num = 0;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ for (gpio_num = 0; gpio_num < num; gpio_num++) {
++ sch_gpio_reg_clear_if_set(RGTPE, gpio_num);
++ sch_gpio_reg_clear_if_set(RGTNE, gpio_num);
++ sch_gpio_reg_clear_if_set(RGGPE, gpio_num);
++ sch_gpio_reg_clear_if_set(RGSMI, gpio_num);
++ sch_gpio_reg_clear_if_set(RGNMIEN, gpio_num);
++ /* clear any pending interrupt */
++ sch_gpio_reg_set(RGTS, gpio_num, 1);
++ }
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++}
++
++void sch_gpio_resume_save_state(struct sch_gpio_resume_int_regvals *regs)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ regs->rgtpe = inb(gpio_ba + RGTPE);
++ regs->rgtne = inb(gpio_ba + RGTNE);
++ regs->rggpe = inb(gpio_ba + RGGPE);
++ regs->rgsmi = inb(gpio_ba + RGSMI);
++ regs->rgnmien = inb(gpio_ba + RGNMIEN);
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++}
++
++void sch_gpio_resume_restore_state(struct sch_gpio_resume_int_regvals *regs)
++{
++ unsigned long flags = 0;
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ outb(regs->rgtpe, gpio_ba + RGTPE);
++ outb(regs->rgtne, gpio_ba + RGTNE);
++ outb(regs->rggpe, gpio_ba + RGGPE);
++ outb(regs->rgsmi, gpio_ba + RGSMI);
++ outb(regs->rgnmien, gpio_ba + RGNMIEN);
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++}
++
++static irqreturn_t sch_gpio_irq_handler(int irq, void *dev_id)
++{
++ int res;
++ int i, ret = IRQ_NONE;
++
++ for (i = 0; i < sch_gpio_core.ngpio; i++) {
++
++ res = sch_gpio_reg_get(CGTS, i);
++ if (res) {
++ /* clear by setting TS to 1 */
++ sch_gpio_reg_set(CGTS, i, 1);
++
++ generic_handle_irq(chip_ptr->irq_base_core + i);
++ ret = IRQ_HANDLED;
++ }
++ }
++
++ for (i = 0; i < sch_gpio_resume.ngpio; i++) {
++
++ res = sch_gpio_reg_get(RGTS, i);
++ if (res) {
++ /* clear by setting TS to 1 */
++ sch_gpio_reg_set(RGTS, i, 1);
++
++ generic_handle_irq(chip_ptr->irq_base_resume + i);
++ ret = IRQ_HANDLED;
++ }
++ }
++
++ return ret;
++}
++
+ static int sch_gpio_probe(struct platform_device *pdev)
+ {
+ struct resource *res;
++ struct sch_gpio *chip;
+ int err, id;
+
++ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
++ if (chip == NULL)
++ return -ENOMEM;
++
++ chip_ptr = chip;
++
++ sch_gpio_core_save_state(&(chip->initial_core));
++ sch_gpio_resume_save_state(&(chip->initial_resume));
++
+ id = pdev->id;
+ if (!id)
+ return -ENODEV;
+@@ -203,46 +615,56 @@ static int sch_gpio_probe(struct platform_device *pdev)
+
+ gpio_ba = res->start;
+
++ irq_num = RESOURCE_IRQ;
++
+ switch (id) {
+- case PCI_DEVICE_ID_INTEL_SCH_LPC:
+- sch_gpio_core.base = 0;
+- sch_gpio_core.ngpio = 10;
+-
+- sch_gpio_resume.base = 10;
+- sch_gpio_resume.ngpio = 4;
+-
+- /*
+- * GPIO[6:0] enabled by default
+- * GPIO7 is configured by the CMC as SLPIOVR
+- * Enable GPIO[9:8] core powered gpios explicitly
+- */
+- outb(0x3, gpio_ba + CGEN + 1);
+- /*
+- * SUS_GPIO[2:0] enabled by default
+- * Enable SUS_GPIO3 resume powered gpio explicitly
+- */
+- outb(0x8, gpio_ba + RGEN);
+- break;
+-
+- case PCI_DEVICE_ID_INTEL_ITC_LPC:
+- sch_gpio_core.base = 0;
+- sch_gpio_core.ngpio = 5;
+-
+- sch_gpio_resume.base = 5;
+- sch_gpio_resume.ngpio = 9;
+- break;
+-
+- case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
+- sch_gpio_core.base = 0;
+- sch_gpio_core.ngpio = 21;
+-
+- sch_gpio_resume.base = 21;
+- sch_gpio_resume.ngpio = 9;
+- break;
+-
+- default:
+- err = -ENODEV;
+- goto err_sch_gpio_core;
++ case PCI_DEVICE_ID_INTEL_SCH_LPC:
++ sch_gpio_core.base = 0;
++ sch_gpio_core.ngpio = 10;
++
++ sch_gpio_resume.base = 10;
++ sch_gpio_resume.ngpio = 4;
++
++ /*
++ * GPIO[6:0] enabled by default
++ * GPIO7 is configured by the CMC as SLPIOVR
++ * Enable GPIO[9:8] core powered gpios explicitly
++ */
++ outb(0x3, gpio_ba + CGEN + 1);
++ /*
++ * SUS_GPIO[2:0] enabled by default
++ * Enable SUS_GPIO3 resume powered gpio explicitly
++ */
++ outb(0x8, gpio_ba + RGEN);
++ break;
++
++ case PCI_DEVICE_ID_INTEL_ITC_LPC:
++ sch_gpio_core.base = 0;
++ sch_gpio_core.ngpio = 5;
++
++ sch_gpio_resume.base = 5;
++ sch_gpio_resume.ngpio = 9;
++ break;
++
++ case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
++ sch_gpio_core.base = 0;
++ sch_gpio_core.ngpio = 21;
++
++ sch_gpio_resume.base = 21;
++ sch_gpio_resume.ngpio = 9;
++ break;
++
++ case PCI_DEVICE_ID_INTEL_QUARK_ILB:
++ sch_gpio_core.base = 0;
++ sch_gpio_core.ngpio = 2;
++
++ sch_gpio_resume.base = 2;
++ sch_gpio_resume.ngpio = 6;
++ break;
++
++ default:
++ err = -ENODEV;
++ goto err_sch_gpio_core;
+ }
+
+ sch_gpio_core.dev = &pdev->dev;
+@@ -256,44 +678,147 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ if (err < 0)
+ goto err_sch_gpio_resume;
+
++ chip->irq_base_core = irq_alloc_descs(-1, 0,
++ sch_gpio_core.ngpio,
++ NUMA_NO_NODE);
++ if (chip->irq_base_core < 0) {
++ dev_err(&pdev->dev, "failure adding GPIO core IRQ descs\n");
++ chip->irq_base_core = -1;
++ goto err_sch_intr_core;
++ }
++
++ chip->irq_base_resume = irq_alloc_descs(-1, 0,
++ sch_gpio_resume.ngpio,
++ NUMA_NO_NODE);
++ if (chip->irq_base_resume < 0) {
++ dev_err(&pdev->dev, "failure adding GPIO resume IRQ descs\n");
++ chip->irq_base_resume = -1;
++ goto err_sch_intr_resume;
++ }
++
++ platform_set_drvdata(pdev, chip);
++
++ err = platform_device_register(&qrk_gpio_restrict_pdev);
++ if (err < 0)
++ goto err_sch_gpio_device_register;
++
++ /* disable interrupts */
++ sch_gpio_core_irq_disable_all(chip, sch_gpio_core.ngpio);
++ sch_gpio_resume_irq_disable_all(chip, sch_gpio_resume.ngpio);
++
++
++ err = request_irq(irq_num, sch_gpio_irq_handler,
++ IRQF_SHARED, KBUILD_MODNAME, chip);
++ if (err != 0) {
++ dev_err(&pdev->dev,
++ "%s request_irq failed\n", __func__);
++ goto err_sch_request_irq;
++ }
++
++ sch_gpio_core_irqs_init(chip, sch_gpio_core.ngpio);
++ sch_gpio_resume_irqs_init(chip, sch_gpio_resume.ngpio);
++
+ return 0;
+
++err_sch_request_irq:
++ platform_device_unregister(&qrk_gpio_restrict_pdev);
++
++err_sch_gpio_device_register:
++ irq_free_descs(chip->irq_base_resume, sch_gpio_resume.ngpio);
++
++err_sch_intr_resume:
++ irq_free_descs(chip->irq_base_core, sch_gpio_core.ngpio);
++
++err_sch_intr_core:
++ err = gpiochip_remove(&sch_gpio_resume);
++ if (err)
++ dev_err(&pdev->dev, "%s failed, %d\n",
++ "resume gpiochip_remove()", err);
++
+ err_sch_gpio_resume:
+ err = gpiochip_remove(&sch_gpio_core);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+- "gpiochip_remove()", err);
++ "core gpiochip_remove()", err);
+
+ err_sch_gpio_core:
+ release_region(res->start, resource_size(res));
+ gpio_ba = 0;
+
++ sch_gpio_resume_restore_state(&(chip->initial_resume));
++ sch_gpio_core_restore_state(&(chip->initial_core));
++
++ kfree(chip);
++ chip_ptr = 0;
++
+ return err;
+ }
+
+ static int sch_gpio_remove(struct platform_device *pdev)
+ {
++ int err = 0;
+ struct resource *res;
++
++ struct sch_gpio *chip = platform_get_drvdata(pdev);
++
+ if (gpio_ba) {
+- int err;
+
+- err = gpiochip_remove(&sch_gpio_core);
++ sch_gpio_resume_irqs_deinit(chip, sch_gpio_resume.ngpio);
++ sch_gpio_core_irqs_deinit(chip, sch_gpio_core.ngpio);
++
++ if (irq_num > 0)
++ free_irq(irq_num, chip);
++
++ platform_device_unregister(&qrk_gpio_restrict_pdev);
++
++ irq_free_descs(chip->irq_base_resume,
++ sch_gpio_resume.ngpio);
++
++ irq_free_descs(chip->irq_base_core, sch_gpio_core.ngpio);
++
++ err = gpiochip_remove(&sch_gpio_resume);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+- "gpiochip_remove()", err);
+- err = gpiochip_remove(&sch_gpio_resume);
++ "resume gpiochip_remove()", err);
++
++ err = gpiochip_remove(&sch_gpio_core);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+- "gpiochip_remove()", err);
++ "core gpiochip_remove()", err);
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+
+ release_region(res->start, resource_size(res));
+ gpio_ba = 0;
+-
+- return err;
+ }
+
++ sch_gpio_resume_restore_state(&(chip->initial_resume));
++ sch_gpio_core_restore_state(&(chip->initial_core));
++
++ kfree(chip);
++
++ chip_ptr = 0;
++
++ return err;
++}
++
++static int sch_gpio_suspend_sys(struct platform_device *pdev,
++ pm_message_t state)
++{
++ sch_gpio_core_save_state(&(chip_ptr->lp_core));
++ sch_gpio_resume_save_state(&(chip_ptr->lp_resume));
++
++ sch_gpio_resume_restore_state(&(chip_ptr->initial_resume));
++ sch_gpio_core_restore_state(&(chip_ptr->initial_core));
++
++ return 0;
++}
++
++static int sch_gpio_resume_sys(struct platform_device *pdev)
++{
++ sch_gpio_resume_restore_state(&(chip_ptr->lp_resume));
++ sch_gpio_core_restore_state(&(chip_ptr->lp_core));
++
+ return 0;
+ }
+
+@@ -304,6 +829,8 @@ static struct platform_driver sch_gpio_driver = {
+ },
+ .probe = sch_gpio_probe,
+ .remove = sch_gpio_remove,
++ .suspend = sch_gpio_suspend_sys,
++ .resume = sch_gpio_resume_sys,
+ };
+
+ 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
new file mode 100644
index 0000000..ec541dc
--- /dev/null
+++ b/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch
@@ -0,0 +1,272 @@
+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
+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(-)
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 682de75..afab416 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -243,13 +243,14 @@ config GPIO_VR41XX
+ Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+
+ config GPIO_SCH
+- tristate "Intel SCH/TunnelCreek/Centerton GPIO"
++ tristate "Intel SCH/TunnelCreek/Centerton/Quark GPIO"
+ depends on PCI && X86
+ select MFD_CORE
+ select LPC_SCH
+ help
+ Say yes here to support GPIO interface on Intel Poulsbo SCH,
+- Intel Tunnel Creek processor or Intel Centerton processor.
++ Intel Tunnel Creek processor, Intel Centerton processor or Intel
++ Quark.
+ The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
+ powered by the core power rail and are turned off during sleep
+ modes (S3 and higher). The remaining four GPIOs are powered by
+@@ -261,6 +262,8 @@ config GPIO_SCH
+ The Intel Centerton processor has a total of 30 GPIO pins.
+ Twenty-one are powered by the core power rail and 9 from the
+ suspend power supply.
++ The Intel Quark has 2 GPIOs powered by the core power well and 6
++ form the suspend power well.
+
+ config GPIO_ICH
+ tristate "Intel ICH GPIO"
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 5359ca7..5e897ff 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -60,11 +60,17 @@ struct gpio_desc {
+ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
+ #define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
+ #define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
++#define FLAG_PULLUP 10 /* Gpio drive is resistive pullup */
++#define FLAG_PULLDOWN 11 /* Gpio drive is resistive pulldown */
++#define FLAG_STRONG 12 /* Gpio drive is strong (fast output) */
++#define FLAG_HIZ 13 /* Gpio drive is Hi-Z (input) */
+
+ #define ID_SHIFT 16 /* add new flags before this one */
+
+ #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
+ #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
++#define GPIO_DRIVE_MASK (BIT(FLAG_PULLUP) | BIT(FLAG_PULLDOWN) \
++ | BIT(FLAG_STRONG) | BIT(FLAG_HIZ))
+
+ #ifdef CONFIG_DEBUG_FS
+ const char *label;
+@@ -243,6 +249,10 @@ static DEFINE_MUTEX(sysfs_lock);
+ * * is read/write as zero/nonzero
+ * * also affects existing and subsequent "falling" and "rising"
+ * /edge configuration
++ * /drive
++ * * sets signal drive mode
++ * * is read/write as "pullup", "pulldown", "strong" or "hiz"
++ *
+ */
+
+ static ssize_t gpio_direction_show(struct device *dev,
+@@ -573,9 +583,85 @@ static ssize_t gpio_active_low_store(struct device *dev,
+ static const DEVICE_ATTR(active_low, 0644,
+ gpio_active_low_show, gpio_active_low_store);
+
++static ssize_t gpio_drive_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ const struct gpio_desc *desc = dev_get_drvdata(dev);
++ ssize_t status;
++
++ mutex_lock(&sysfs_lock);
++
++ if (!test_bit(FLAG_EXPORT, &desc->flags)) {
++ status = -EIO;
++ } else {
++ if (test_bit(FLAG_PULLUP, &desc->flags))
++ status = sprintf(buf, "pullup\n");
++ else if (test_bit(FLAG_PULLDOWN, &desc->flags))
++ status = sprintf(buf, "pulldown\n");
++ else if (test_bit(FLAG_STRONG, &desc->flags))
++ status = sprintf(buf, "strong\n");
++ else if (test_bit(FLAG_HIZ, &desc->flags))
++ status = sprintf(buf, "hiz\n");
++ else
++ status = -EINVAL;
++ }
++
++ mutex_unlock(&sysfs_lock);
++ return status;
++}
++
++static ssize_t gpio_drive_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ struct gpio_desc *desc = dev_get_drvdata(dev);
++ unsigned gpio = desc - gpio_desc;
++ ssize_t status;
++
++ mutex_lock(&sysfs_lock);
++
++ if (!test_bit(FLAG_EXPORT, &desc->flags))
++ status = -EIO;
++ else {
++ if (sysfs_streq(buf, "pullup")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLUP);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_PULLUP, &desc->flags);
++ }
++ } else if (sysfs_streq(buf, "pulldown")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLDOWN);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_PULLDOWN, &desc->flags);
++ }
++ } else if (sysfs_streq(buf, "strong")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_STRONG);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_STRONG, &desc->flags);
++ }
++ } else if (sysfs_streq(buf, "hiz")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_HIZ);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_HIZ, &desc->flags);
++ }
++ } else {
++ status = -EINVAL;
++ }
++ }
++
++ mutex_unlock(&sysfs_lock);
++ return status ? : size;
++}
++
++static const DEVICE_ATTR(drive, 0644,
++ gpio_drive_show, gpio_drive_store);
++
+ static const struct attribute *gpio_attrs[] = {
+ &dev_attr_value.attr,
+ &dev_attr_active_low.attr,
++ &dev_attr_drive.attr,
+ NULL,
+ };
+
+@@ -1677,6 +1763,50 @@ fail:
+ }
+ EXPORT_SYMBOL_GPL(gpio_set_debounce);
+
++/**
++ * gpio_set_drive - sets drive @mode for a @gpio
++ * @gpio: the gpio to set the drive mode
++ * @mode: the drive mode
++ */
++int gpio_set_drive(unsigned gpio, unsigned mode)
++{
++ unsigned long flags;
++ struct gpio_chip *chip;
++ struct gpio_desc *desc = &gpio_desc[gpio];
++ int status = -EINVAL;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ if (!gpio_is_valid(gpio))
++ goto fail;
++ chip = desc->chip;
++ if (!chip || !chip->set || !chip->set_drive)
++ goto fail;
++ gpio -= chip->base;
++ if (gpio >= chip->ngpio)
++ goto fail;
++ status = gpio_ensure_requested(desc, gpio);
++ if (status < 0)
++ goto fail;
++
++ /* now we know the gpio is valid and chip won't vanish */
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++ might_sleep_if(chip->can_sleep);
++
++ return chip->set_drive(chip, gpio, mode);
++
++fail:
++ spin_unlock_irqrestore(&gpio_lock, flags);
++ if (status)
++ pr_debug("%s: gpio-%d status %d\n",
++ __func__, gpio, status);
++
++ return status;
++}
++EXPORT_SYMBOL_GPL(gpio_set_drive);
++
+ /* I/O calls are only valid after configuration completed; the relevant
+ * "is this a valid GPIO" error checks should already have been done.
+ *
+diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
+index 20ca766..8265ccc 100644
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -65,6 +65,7 @@ struct device_node;
+ * @direction_output: configures signal "offset" as output, or returns error
+ * @set_debounce: optional hook for setting debounce time for specified gpio in
+ * interrupt triggered gpio chips
++ * @set_drive: optional hook for setting the drive signal for "offset"
+ * @set: assigns output value for signal "offset"
+ * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
+ * implementation may not sleep
+@@ -113,6 +114,8 @@ struct gpio_chip {
+ unsigned offset, int value);
+ int (*set_debounce)(struct gpio_chip *chip,
+ unsigned offset, unsigned debounce);
++ int (*set_drive)(struct gpio_chip *chip,
++ unsigned offset, unsigned mode);
+
+ void (*set)(struct gpio_chip *chip,
+ unsigned offset, int value);
+@@ -172,6 +175,7 @@ extern int gpio_direction_input(unsigned gpio);
+ extern int gpio_direction_output(unsigned gpio, int value);
+
+ extern int gpio_set_debounce(unsigned gpio, unsigned debounce);
++extern int gpio_set_drive(unsigned gpio, unsigned mode);
+
+ extern int gpio_get_value_cansleep(unsigned gpio);
+ extern void gpio_set_value_cansleep(unsigned gpio, int value);
+diff --git a/include/linux/gpio.h b/include/linux/gpio.h
+index bfe6656..cadd9d2 100644
+--- a/include/linux/gpio.h
++++ b/include/linux/gpio.h
+@@ -27,6 +27,11 @@
+ #define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
+ #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
+
++#define GPIOF_DRIVE_PULLUP (1 << 6)
++#define GPIOF_DRIVE_PULLDOWN (1 << 7)
++#define GPIOF_DRIVE_STRONG (1 << 8)
++#define GPIOF_DRIVE_HIZ (1 << 9)
++
+ /**
+ * struct gpio - a structure describing a GPIO with configuration
+ * @gpio: the GPIO number
+@@ -156,6 +161,11 @@ static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+ return -ENOSYS;
+ }
+
++static inline int gpio_set_drive(unsigned gpio, unsigned mode)
++{
++ return -ENOSYS;
++}
++
+ 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
new file mode 100644
index 0000000..8488759
--- /dev/null
+++ b/recipes-kernel/linux/files/0016-Quark-GIP-Cypress-I-O-expander-quark.patch
@@ -0,0 +1,3822 @@
+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
+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/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(-)
+ 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
+ create mode 100644 drivers/mfd/intel_qrk_gip_gpio.c
+ 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 include/linux/mfd/cy8c9540a.h
+ create mode 100644 include/linux/mfd/intel_qrk_gip_pdata.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index ff553ba..b8029bd 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -907,6 +907,44 @@ config MFD_TIMBERDALE
+ The timberdale FPGA can be found on the Intel Atom development board
+ for in-vehicle infontainment, called Russellville.
+
++config CY8C9540A
++ tristate "Cypress CY8C9540 GPIO/PWM expander"
++ depends on GPIOLIB
++ depends on I2C
++ depends on PWM
++ help
++ 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 INTEL_QRK_GIP
++ tristate "Intel Quark GIP"
++ depends on PCI && X86 && INTEL_QUARK_X1000_SOC
++ depends on I2C
++ select GENERIC_IRQ_CHIP
++ help
++ GIP driver for Quark SoC.
++ Quark GIP is a single PCI function exporting a GPIO and an I2C
++ controller, namely Synopsys DesignWare GPIO and Synopsys DesignWare
++ I2C. The GPIO interface exports a total amount of 8 interrupt-capable
++ GPIOs.
++
++config INTEL_QRK_GIP_TEST
++ tristate "Intel Quark GIP support for Integration Testing"
++ depends on INTEL_QRK_GIP
++ select I2C_CHARDEV
++ select GPIO_SYSFS
++ select SPI
++ select SPI_BITBANG
++ select SPI_GPIO
++ select SPI_MASTER
++ select SPI_SPIDEV
++ help
++ Quark GIP automated Integration Testing package.
++ It selects kernel components needed for GPIO and I2C tests as per
++ Integration Test Specification, and it also adds a kernel-space
++ facility for testing the GPIO.
++ Note this module is also used to test the Quark Legacy GPIO.
++
+ config LPC_SCH
+ tristate "Intel SCH LPC"
+ depends on PCI
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 8b977f8..b17d50c 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -123,6 +123,14 @@ 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
++obj-$(CONFIG_INTEL_QRK_GIP) += intel_qrk_gip.o
++intel_qrk_gip-objs := intel_qrk_gip_core.o \
++ intel_qrk_gip_gpio.o \
++ intel_qrk_gip_i2c.o \
++ ../i2c/busses/i2c-designware-core.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_qrk_gip_pdata.o
++obj-$(CONFIG_INTEL_QRK_GIP_TEST)+=intel_qrk_gip_test.o
+ obj-$(CONFIG_LPC_SCH) += lpc_sch.o
+ obj-$(CONFIG_LPC_ICH) += lpc_ich.o
+ 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
+--- /dev/null
++++ b/drivers/mfd/cy8c9540a.c
+@@ -0,0 +1,970 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++/*
++ * Driver for Cypress CY8C9540A I/O Expander and PWM
++ *
++ * The I/O Expander is I2C-controlled and provides 40 interrupt-capable GPIOs,
++ * 8 PWMs and an EEPROM.
++ * Note the device only supports I2C standard speed 100kHz.
++ *
++ * Based on gpio-adp5588.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/gpio.h>
++#include <linux/kernel.h>
++#include <linux/mfd/cy8c9540a.h>
++#include <linux/module.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++
++#define DRV_NAME "cy8c9540a"
++
++/* CY8C9540A settings */
++#define NGPIO 40
++#define PWM_MAX_PERIOD 0xff
++#define DEVID_FAMILY_CY8C9540A 0x40
++#define DEVID_FAMILY_MASK 0xf0
++#define NPORTS 6
++#define PWM_CLK 0x00 /* see resulting PWM_TCLK_NS */
++#define PWM_TCLK_NS 31250 /* 32kHz */
++
++/* Register offset */
++#define REG_INPUT_PORT0 0x00
++#define REG_OUTPUT_PORT0 0x08
++#define REG_INTR_STAT_PORT0 0x10
++#define REG_PORT_SELECT 0x18
++#define REG_INTR_MASK 0x19
++#define REG_SELECT_PWM 0x1a
++#define REG_PIN_DIR 0x1c
++#define REG_DRIVE_PULLUP 0x1d
++#define REG_PWM_SELECT 0x28
++#define REG_PWM_CLK 0x29
++#define REG_PWM_PERIOD 0x2a
++#define REG_PWM_PULSE_W 0x2b
++#define REG_ENABLE 0x2d
++#define REG_DEVID_STAT 0x2e
++#define REG_CMD 0x30
++
++/* Commands */
++#define CMD_W_EEPROM_POR 0x03
++#define CMD_R_EEPROM_POR 0x04
++#define CMD_RECONF 0x07
++
++/* Max retries after I2C NAK */
++#define MAX_RETRIES 3
++
++/*
++ * Wait time for device to be ready.
++ * Note the time the part takes depends on the user configuration (mainly on
++ * the number of active interrupts). The minimum delay here covers the
++ * worst-case scenario.
++ */
++#define SLEEP_US_MIN 4000
++#define SLEEP_US_MAX 4500
++
++/* Command string to store platform POR settings */
++#define POR_CMD_W_OFFS 2
++static u8 por_set[CY8C9540A_POR_SETTINGS_LEN + POR_CMD_W_OFFS] = {
++ [0] = REG_CMD,
++ [1] = CMD_W_EEPROM_POR,
++};
++
++struct cy8c9540a {
++ struct i2c_client *client;
++ struct gpio_chip gpio_chip;
++ struct pwm_chip pwm_chip;
++ struct mutex lock;
++ /* IRQ base stored from platform data */
++ int irq_base;
++ /* protect serialized access to the interrupt controller bus */
++ struct mutex irq_lock;
++ /* cached output registers */
++ u8 outreg_cache[NPORTS];
++ /* cached IRQ mask */
++ u8 irq_mask_cache[NPORTS];
++ /* IRQ mask to be applied */
++ u8 irq_mask[NPORTS];
++ /* Descriptor for raw i2c transactions */
++ struct i2c_msg i2c_segments[2];
++ /* POR settings stored in the EEPROM */
++ u8 por_stored[CY8C9540A_POR_SETTINGS_LEN];
++ /* PWM-to-GPIO mapping (0 == first gpio pin) */
++ int pwm2gpio_mapping[CY8C9540A_NPWM];
++};
++
++/* Per-port GPIO offset */
++static const u8 cy8c9540a_port_offs[] = {
++ 0,
++ 8,
++ 16,
++ 20,
++ 28,
++ 36,
++};
++
++static inline u8 cypress_get_port(unsigned gpio)
++{
++ u8 i = 0;
++ for (i = 0; i < sizeof(cy8c9540a_port_offs) - 1; i ++) {
++ if (! (gpio / cy8c9540a_port_offs[i + 1]))
++ break;
++ }
++ return i;
++}
++
++static inline u8 cypress_get_offs(unsigned gpio, u8 port)
++{
++ return gpio - cy8c9540a_port_offs[port];
++}
++
++static int cy8c9540a_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
++{
++ s32 ret = 0;
++ u8 port = 0;
++ u8 in_reg = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++
++ port = cypress_get_port(gpio);
++ in_reg = REG_INPUT_PORT0 + port;
++
++ ret = i2c_smbus_read_byte_data(client, in_reg);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read input port%u\n", in_reg);
++ }
++
++ return !!(ret & BIT(cypress_get_offs(gpio, port)));
++}
++
++static void cy8c9540a_gpio_set_value(struct gpio_chip *chip,
++ unsigned gpio, int val)
++{
++ s32 ret = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++ u8 port = cypress_get_port(gpio);
++ u8 out_reg = REG_OUTPUT_PORT0 + port;
++
++ mutex_lock(&dev->lock);
++
++ if (val) {
++ dev->outreg_cache[port] |= BIT(cypress_get_offs(gpio, port));
++ } else {
++ dev->outreg_cache[port] &= ~BIT(cypress_get_offs(gpio, port));
++ }
++
++ ret = i2c_smbus_write_byte_data(client, out_reg,
++ dev->outreg_cache[port]);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write output port%u\n", port);
++ }
++
++ mutex_unlock(&dev->lock);
++}
++
++static int cy8c9540a_gpio_set_drive(struct gpio_chip *chip, unsigned gpio,
++ unsigned mode)
++{
++ s32 ret = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++ u8 port = cypress_get_port(gpio);
++ u8 pin = cypress_get_offs(gpio, port);
++ u8 offs = 0;
++ u8 val = 0;
++
++ switch(mode) {
++ case GPIOF_DRIVE_PULLUP:
++ offs = 0x0;
++ break;
++ case GPIOF_DRIVE_STRONG:
++ offs = 0x4;
++ break;
++ case GPIOF_DRIVE_HIZ:
++ offs = 0x6;
++ break;
++ default:
++ /*
++ * See databook for alternative modes. This driver won't
++ * support them though.
++ */
++ return -EINVAL;
++ break;
++ }
++
++ mutex_lock(&dev->lock);
++
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", port);
++ goto end;
++ }
++
++ ret = i2c_smbus_read_byte_data(client, REG_DRIVE_PULLUP + offs);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read pin direction\n");
++ goto end;
++ }
++
++ val = (u8)(ret | BIT(pin));
++
++ ret = i2c_smbus_write_byte_data(client, REG_DRIVE_PULLUP + offs, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't set drive mode port %u\n", port);
++ goto end;
++ }
++
++ ret = 0;
++
++end:
++ mutex_unlock(&dev->lock);
++ return ret;
++}
++
++static int cy8c9540a_gpio_direction(struct gpio_chip *chip, unsigned gpio,
++ int out, int val)
++{
++ s32 ret = 0;
++ u8 pins = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++ u8 port = cypress_get_port(gpio);
++
++ ret = cy8c9540a_gpio_set_drive(chip, gpio, out ?
++ GPIOF_DRIVE_STRONG : GPIOF_DRIVE_HIZ);
++ if (ret) {
++ return ret;
++ }
++
++ mutex_lock(&dev->lock);
++
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", port);
++ goto end;
++ }
++
++ ret = i2c_smbus_read_byte_data(client, REG_PIN_DIR);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read pin direction\n");
++ goto end;
++ }
++
++ pins = (u8)ret & 0xff;
++ if (out) {
++ pins &= ~BIT(cypress_get_offs(gpio, port));
++ } else {
++ pins |= BIT(cypress_get_offs(gpio, port));
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_PIN_DIR, pins);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write pin direction\n");
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++ return ret;
++}
++
++static int cy8c9540a_gpio_direction_output(struct gpio_chip *chip,
++ unsigned gpio, int val)
++{
++ return cy8c9540a_gpio_direction(chip, gpio, 1, val);
++}
++
++static int cy8c9540a_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
++{
++ return cy8c9540a_gpio_direction(chip, gpio, 0, 0);
++}
++
++static void cy8c9540a_irq_bus_lock(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ mutex_lock(&dev->irq_lock);
++}
++
++static void cy8c9540a_irq_bus_sync_unlock(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ struct i2c_client *client = dev->client;
++ int ret = 0;
++ int i = 0;
++
++ for (i = 0; i < NPORTS; i++) {
++ if (dev->irq_mask_cache[i] ^ dev->irq_mask[i]) {
++ dev->irq_mask_cache[i] = dev->irq_mask[i];
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, i);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", i);
++ goto end;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_INTR_MASK, dev->irq_mask[i]);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write int mask on port %u\n", i);
++ goto end;
++ }
++
++ }
++ }
++
++end:
++ mutex_unlock(&dev->irq_lock);
++}
++
++static void cy8c9540a_irq_mask(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ unsigned gpio = d->irq - dev->irq_base;
++ u8 port = cypress_get_port(gpio);
++
++ dev->irq_mask[port] |= BIT(cypress_get_offs(gpio, port));
++}
++
++static void cy8c9540a_irq_unmask(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ unsigned gpio = d->irq - dev->irq_base;
++ u8 port = cypress_get_port(gpio);
++
++ dev->irq_mask[port] &= ~BIT(cypress_get_offs(gpio, port));
++}
++
++static int cy8c9540a_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ return dev->irq_base + gpio;
++}
++
++static int cy8c9540a_irq_set_type(struct irq_data *d, unsigned int type)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ int ret = 0;
++
++ if ((type != IRQ_TYPE_EDGE_BOTH)) {
++ dev_err(&dev->client->dev, "irq %d: unsupported type %d\n",
++ d->irq, type);
++ ret = -EINVAL;
++ goto end;
++ }
++
++end:
++ return ret;
++}
++
++static struct irq_chip cy8c9540a_irq_chip = {
++ .name = "cy8c9540a-irq",
++ .irq_mask = cy8c9540a_irq_mask,
++ .irq_unmask = cy8c9540a_irq_unmask,
++ .irq_bus_lock = cy8c9540a_irq_bus_lock,
++ .irq_bus_sync_unlock = cy8c9540a_irq_bus_sync_unlock,
++ .irq_set_type = cy8c9540a_irq_set_type,
++};
++
++static irqreturn_t cy8c9540a_irq_handler(int irq, void *devid)
++{
++ struct cy8c9540a *dev = devid;
++ u8 stat[NPORTS], pending = 0;
++ unsigned port = 0, gpio = 0, gpio_irq = 0;
++ int ret = 0;
++
++ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_INTR_STAT_PORT0,
++ NPORTS, stat); /* W1C */
++ if (ret < 0) {
++ memset(stat, 0, sizeof(stat));
++ }
++
++ ret = IRQ_NONE;
++
++ for (port = 0; port < NPORTS; port ++) {
++ /* Databook doesn't specify if this is a post-mask status
++ register or not. Consider it 'raw' for safety. */
++ mutex_lock(&dev->irq_lock);
++ pending = stat[port] & (~dev->irq_mask[port]);
++ mutex_unlock(&dev->irq_lock);
++
++ while (pending) {
++ ret = IRQ_HANDLED;
++ gpio = __ffs(pending);
++ pending &= ~BIT(gpio);
++ gpio_irq = dev->irq_base + cy8c9540a_port_offs[port]
++ + gpio;
++ handle_nested_irq(gpio_irq);
++ }
++ }
++
++ return ret;
++}
++
++static int cy8c9540a_irq_setup(struct cy8c9540a *dev)
++{
++ struct i2c_client *client = dev->client;
++ u8 dummy[NPORTS];
++ unsigned gpio = 0;
++ int ret = 0;
++ int i = 0;
++
++ mutex_init(&dev->irq_lock);
++
++ /* Clear interrupt state */
++
++ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_INTR_STAT_PORT0,
++ NPORTS, dummy); /* W1C */
++ if (ret < 0) {
++ dev_err(&client->dev, "couldn't clear int status\n");
++ goto err;
++ }
++
++ /* Initialise interrupt mask */
++
++ memset(dev->irq_mask_cache, 0xff, sizeof(dev->irq_mask_cache));
++ memset(dev->irq_mask, 0xff, sizeof(dev->irq_mask));
++ for (i = 0; i < NPORTS; i++) {
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, i);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", i);
++ goto err;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_INTR_MASK, dev->irq_mask[i]);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write int mask on port %u\n", i);
++ goto err;
++ }
++ }
++
++ /* Allocate IRQ descriptors for Cypress GPIOs and set handler */
++
++ ret = irq_alloc_descs(dev->irq_base, dev->irq_base, NGPIO, 0);
++ if (ret < 0) {
++ dev_err(&client->dev, "failed to allocate IRQ numbers\n");
++ goto err;
++ }
++
++ for (gpio = 0; gpio < NGPIO; gpio++) {
++ int irq = gpio + dev->irq_base;
++ irq_set_chip_data(irq, dev);
++ irq_set_chip_and_handler(irq, &cy8c9540a_irq_chip,
++ handle_edge_irq);
++ irq_set_nested_thread(irq, 1);
++ irq_set_noprobe(irq);
++ }
++
++ ret = request_threaded_irq(client->irq, NULL, cy8c9540a_irq_handler,
++ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
++ dev_name(&client->dev), dev);
++ if (ret) {
++ dev_err(&client->dev, "failed to request irq %d\n",
++ client->irq);
++ goto err_free_irq_descs;
++ }
++
++ return 0;
++
++err_free_irq_descs:
++ irq_free_descs(dev->irq_base, NGPIO);
++err:
++ mutex_destroy(&dev->irq_lock);
++ return ret;
++}
++
++static void cy8c9540a_irq_teardown(struct cy8c9540a *dev)
++{
++ struct i2c_client *client = dev->client;
++
++ irq_free_descs(dev->irq_base, NGPIO);
++ free_irq(client->irq, dev);
++ mutex_destroy(&dev->irq_lock);
++}
++
++static int cy8c9540a_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ int ret = 0;
++ int period = 0, duty = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm >= CY8C9540A_NPWM) {
++ return -EINVAL;
++ }
++
++ period = period_ns / PWM_TCLK_NS;
++ duty = duty_ns / PWM_TCLK_NS;
++
++ /*
++ * Check period's upper bound. Note the duty cycle is already sanity
++ * checked by the PWM framework.
++ */
++ if (period > PWM_MAX_PERIOD) {
++ dev_err(&client->dev, "period must be within [0-%d]ns\n",
++ PWM_MAX_PERIOD * PWM_TCLK_NS);
++ return -EINVAL;
++ }
++
++ mutex_lock(&dev->lock);
++
++ ret = i2c_smbus_write_byte_data(client, REG_PWM_SELECT, (u8)pwm->pwm);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to REG_PWM_SELECT\n");
++ goto end;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_PWM_PERIOD, (u8)period);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to REG_PWM_PERIOD\n");
++ goto end;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_PWM_PULSE_W, (u8)duty);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to REG_PWM_PULSE_W\n");
++ goto end;
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++
++ return ret;
++}
++
++static int cy8c9540a_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ s32 ret = 0;
++ int gpio = 0;
++ int port = 0, pin = 0;
++ u8 out_reg = 0;
++ u8 val = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm >= CY8C9540A_NPWM) {
++ return -EINVAL;
++ }
++
++ gpio = dev->pwm2gpio_mapping[pwm->pwm];
++ port = cypress_get_port(gpio);
++ pin = cypress_get_offs(gpio, port);
++ out_reg = REG_OUTPUT_PORT0 + port;
++
++ /* Set pin as output driving high */
++ ret = cy8c9540a_gpio_direction(&dev->gpio_chip, gpio, 1, 1);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't set pwm%u as output\n", pwm->pwm);
++ return ret;
++ }
++
++ mutex_lock(&dev->lock);
++
++ /* Enable PWM */
++ ret = i2c_smbus_read_byte_data(client, REG_SELECT_PWM);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read REG_SELECT_PWM\n");
++ goto end;
++ }
++ val = (u8)(ret | BIT((u8)pin));
++ ret = i2c_smbus_write_byte_data(client, REG_SELECT_PWM, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to SELECT_PWM\n");
++ goto end;
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++
++ return ret;
++}
++
++static void cy8c9540a_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ s32 ret = 0;
++ int gpio = 0;
++ int port = 0, pin = 0;
++ u8 val = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm >= CY8C9540A_NPWM) {
++ return;
++ }
++
++ gpio = dev->pwm2gpio_mapping[pwm->pwm];
++ if (CY8C9540A_PWM_UNUSED == gpio) {
++ dev_err(&client->dev, "pwm%d is unused\n", pwm->pwm);
++ return;
++ }
++
++ port = cypress_get_port(gpio);
++ pin = cypress_get_offs(gpio, port);
++
++ mutex_lock(&dev->lock);
++
++ /* Disable PWM */
++ ret = i2c_smbus_read_byte_data(client, REG_SELECT_PWM);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read REG_SELECT_PWM\n");
++ goto end;
++ }
++ val = (u8)(ret & ~BIT((u8)pin));
++ ret = i2c_smbus_write_byte_data(client, REG_SELECT_PWM, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to SELECT_PWM\n");
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++
++ return;
++}
++
++/*
++ * Some PWMs may be unavailable. Prevent user from reserving them.
++ */
++static int cy8c9540a_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ int gpio = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm >= CY8C9540A_NPWM) {
++ return -EINVAL;
++ }
++
++ gpio = dev->pwm2gpio_mapping[pwm->pwm];
++ if (CY8C9540A_PWM_UNUSED == gpio) {
++ dev_err(&client->dev, "pwm%d unavailable\n", pwm->pwm);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static const struct pwm_ops cy8c9540a_pwm_ops = {
++ .request = cy8c9540a_pwm_request,
++ .config = cy8c9540a_pwm_config,
++ .enable = cy8c9540a_pwm_enable,
++ .disable = cy8c9540a_pwm_disable,
++};
++
++/*
++ * cy8c9540a_set_por_default
++ *
++ * Ensure the expander is using platform-specific POR settings.
++ *
++ * Note SMBUS max transaction length is 32 bytes, so we have to fall back to
++ * raw i2c transfers.
++ */
++static int cy8c9540a_set_por_default(struct cy8c9540a *dev)
++{
++ int ret = 0;
++ struct i2c_client *client = dev->client;
++ struct cy8c9540a_pdata *pdata = client->dev.platform_data;
++ int i = 0;
++ int segments = -1;
++ int crc_index = sizeof(por_set) - 1;
++ u8 reg_cmd_r_por[] = { REG_CMD, CMD_R_EEPROM_POR };
++
++ /* Populate platform POR setting table */
++ memcpy(por_set + POR_CMD_W_OFFS, pdata->por_default,
++ sizeof(pdata->por_default));
++
++ /* Read POR settings stored in EEPROM */
++ dev->i2c_segments[0].addr = client->addr;
++ dev->i2c_segments[0].flags = 0; /* write */
++ dev->i2c_segments[0].len = sizeof(reg_cmd_r_por);
++ dev->i2c_segments[0].buf = reg_cmd_r_por;
++ dev->i2c_segments[1].addr = client->addr;
++ dev->i2c_segments[1].flags = I2C_M_RD;
++ dev->i2c_segments[1].len = sizeof(dev->por_stored);
++ dev->i2c_segments[1].buf = dev->por_stored;
++ segments = 2;
++ ret = i2c_transfer(client->adapter, dev->i2c_segments, segments);
++ if (segments != ret) {
++ dev_err(&client->dev, "can't read POR settings (ret=%d)\n", ret);
++ goto end;
++ } else {
++ ret = 0;
++ }
++
++ /* Compute CRC for platform-defined POR settings */
++ por_set[crc_index] = 0;
++ for (i = POR_CMD_W_OFFS; i < crc_index; i ++) {
++ por_set[crc_index] ^= por_set[i];
++ }
++
++ /* Compare POR settings with platform-defined ones */
++ for (i = 0; i < sizeof(dev->por_stored); i ++) {
++ if (dev->por_stored[i] != por_set[i + POR_CMD_W_OFFS]) {
++ break;
++ }
++ }
++ if (sizeof(dev->por_stored) == i) {
++ goto end;
++ }
++
++ /* Update POR settings to EEPROM */
++
++ dev_info(&client->dev, "updating EEPROM with platform POR settings\n");
++
++ /* Store default POR settings into EEPROM */
++ dev->i2c_segments[0].addr = client->addr;
++ dev->i2c_segments[0].flags = 0; /* write */
++ dev->i2c_segments[0].len = sizeof(por_set);
++ dev->i2c_segments[0].buf = por_set;
++ segments = 1;
++ ret = i2c_transfer(client->adapter, dev->i2c_segments, segments);
++ if (segments != ret) {
++ dev_err(&client->dev, "can't write POR settings (ret=%d)\n", ret);
++ goto end;
++ } else {
++ ret = 0;
++ }
++
++ /* Reconfigure device with newly stored POR settings */
++ for (i = 0; i < MAX_RETRIES; i++) {
++ usleep_range(SLEEP_US_MIN, SLEEP_US_MAX);
++
++ ret = i2c_smbus_write_byte_data(client, REG_CMD, CMD_RECONF);
++ if (0 == ret) {
++ break;
++ }
++ }
++
++ if (ret < 0) {
++ dev_err(&client->dev, "can't reconfigure device\n");
++ }
++
++end:
++ return ret;
++}
++
++/*
++ * cy8c9540a_setup
++ *
++ * Initialise the device with default setup.
++ * No need to roll back if this fails.
++ */
++static int cy8c9540a_setup(struct cy8c9540a *dev)
++{
++ int ret = 0;
++ struct i2c_client *client = dev->client;
++ const u8 eeprom_enable_seq[] = {0x43, 0x4D, 0x53, 0x2};
++
++ /* Test/set platform-specific POR settings */
++ ret = cy8c9540a_set_por_default(dev);
++ if (ret) {
++ dev_err(&client->dev, "can't set POR settings (err=%d)\n", ret);
++ goto end;
++ }
++
++ /* Cache the output registers */
++ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_OUTPUT_PORT0,
++ sizeof(dev->outreg_cache),
++ dev->outreg_cache);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't cache output registers\n");
++ goto end;
++ }
++
++ /* Enable the EEPROM */
++ ret = i2c_smbus_write_i2c_block_data(client, REG_ENABLE,
++ sizeof(eeprom_enable_seq),
++ eeprom_enable_seq);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't enable EEPROM\n");
++ goto end;
++ }
++
++end:
++ return ret;
++}
++
++static int cy8c9540a_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct cy8c9540a *dev;
++ struct gpio_chip *gc;
++ struct cy8c9540a_pdata *pdata = client->dev.platform_data;
++ int ret = 0;
++ s32 dev_id = 0;
++
++ if (NULL == pdata) {
++ pr_err("%s: platform data is missing\n", __func__);
++ return -EINVAL;
++ }
++
++ if (!i2c_check_functionality(client->adapter,
++ I2C_FUNC_I2C |
++ I2C_FUNC_SMBUS_I2C_BLOCK |
++ I2C_FUNC_SMBUS_BYTE_DATA)) {
++ dev_err(&client->dev, "i2c adapter doesn't support required "
++ "functionality\n");
++ return -EIO;
++ }
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (dev == NULL) {
++ dev_err(&client->dev, "failed to alloc memory\n");
++ return -ENOMEM;
++ }
++
++ dev->client = client;
++ dev->irq_base = pdata->irq_base;
++
++ gc = &dev->gpio_chip;
++ gc->direction_input = cy8c9540a_gpio_direction_input;
++ gc->direction_output = cy8c9540a_gpio_direction_output;
++ gc->get = cy8c9540a_gpio_get_value;
++ gc->set = cy8c9540a_gpio_set_value;
++ gc->set_drive = cy8c9540a_gpio_set_drive;
++
++ gc->can_sleep = 1;
++
++ gc->base = pdata->gpio_base;
++ gc->ngpio = NGPIO;
++ gc->label = client->name;
++ gc->owner = THIS_MODULE;
++ gc->to_irq = cy8c9540a_gpio_to_irq;
++
++ mutex_init(&dev->lock);
++
++ /* Whoami */
++ dev_id = i2c_smbus_read_byte_data(client, REG_DEVID_STAT);
++ if (dev_id < 0) {
++ dev_err(&client->dev, "can't read device ID\n");
++ ret = dev_id;
++ goto err;
++ }
++ dev_info(&client->dev, "dev_id=0x%x\n", dev_id & 0xff);
++ if (DEVID_FAMILY_CY8C9540A != (dev_id & DEVID_FAMILY_MASK)) {
++ dev_err(&client->dev, "unknown/unsupported dev_id 0x%x\n",
++ dev_id & 0xff);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ ret = cy8c9540a_setup(dev);
++ if (ret) {
++ goto err;
++ }
++
++ ret = cy8c9540a_irq_setup(dev);
++ if (ret) {
++ goto err;
++ }
++ ret = gpiochip_add(&dev->gpio_chip);
++ if (ret) {
++ dev_err(&client->dev, "gpiochip_add failed %d\n", ret);
++ goto err_irq;
++ }
++
++ dev->pwm_chip.dev = &client->dev;
++ dev->pwm_chip.ops = &cy8c9540a_pwm_ops;
++ dev->pwm_chip.base = pdata->pwm_base;
++ dev->pwm_chip.npwm = CY8C9540A_NPWM;
++
++ /* Populate platform-specific PWM-to-GPIO mapping table */
++ memcpy(dev->pwm2gpio_mapping, pdata->pwm2gpio_mapping, sizeof(pdata->pwm2gpio_mapping));
++
++ ret = pwmchip_add(&dev->pwm_chip);
++ if (ret) {
++ dev_err(&client->dev, "pwmchip_add failed %d\n", ret);
++ goto err_gpiochip;
++ }
++
++ i2c_set_clientdata(client, dev);
++
++ return 0;
++
++err_gpiochip:
++ if(gpiochip_remove(&dev->gpio_chip))
++ dev_warn(&client->dev, "gpiochip_remove failed\n");
++err_irq:
++ cy8c9540a_irq_teardown(dev);
++err:
++ mutex_destroy(&dev->lock);
++ kfree(dev);
++
++ return ret;
++}
++
++static int cy8c9540a_remove(struct i2c_client *client)
++{
++ struct cy8c9540a *dev = i2c_get_clientdata(client);
++ int ret = 0;
++ int err = 0;
++
++ ret = pwmchip_remove(&dev->pwm_chip);
++ if (ret < 0) {
++ dev_err(&client->dev, "pwmchip_remove failed %d\n", ret);
++ err = ret;
++ }
++
++ ret = gpiochip_remove(&dev->gpio_chip);
++ if (ret) {
++ dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
++ err = ret;
++ }
++
++ cy8c9540a_irq_teardown(dev);
++
++ mutex_destroy(&dev->lock);
++ kfree(dev);
++
++ return err;
++}
++
++static const struct i2c_device_id cy8c9540a_id[] = {
++ {DRV_NAME, 0},
++ {}
++};
++
++MODULE_DEVICE_TABLE(i2c, cy8c9540a_id);
++
++static struct i2c_driver cy8c9540a_driver = {
++ .driver = {
++ .name = DRV_NAME,
++ },
++ .probe = cy8c9540a_probe,
++ .remove = cy8c9540a_remove,
++ .id_table = cy8c9540a_id,
++};
++
++module_i2c_driver(cy8c9540a_driver);
++
++MODULE_AUTHOR("Josef Ahmad <josef.ahmad@linux.intel.com>");
++MODULE_DESCRIPTION("GPIO/PWM driver for CY8C9540A I/O expander");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/mfd/intel_qrk_gip.h b/drivers/mfd/intel_qrk_gip.h
+new file mode 100644
+index 0000000..d1e8316
+--- /dev/null
++++ b/drivers/mfd/intel_qrk_gip.h
+@@ -0,0 +1,104 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark GIP (GPIO/I2C) driver
++ */
++
++#ifndef __INTEL_QRKGIP_H__
++#define __INTEL_QRKGIP_H__
++
++#include <linux/i2c.h>
++#include <linux/mfd/intel_qrk_gip_pdata.h>
++#include <linux/pci.h>
++#include "../i2c/busses/i2c-designware-core.h"
++
++/* PCI BAR for register base address */
++#define GIP_I2C_BAR 0
++#define GIP_GPIO_BAR 1
++
++/**
++ * intel_qrk_gpio_probe
++ *
++ * @param pdev: Pointer to GIP PCI device
++ * @return 0 success < 0 failure
++ *
++ * Perform GPIO-specific probing on behalf of the top-level GIP driver.
++ */
++int intel_qrk_gpio_probe(struct pci_dev *pdev);
++
++/**
++ * intel_qrk_gpio_remove
++ *
++ * @param pdev: Pointer to GIP PCI device
++ *
++ * Perform GPIO-specific resource release on behalf of the top-level GIP driver.
++ */
++void intel_qrk_gpio_remove(struct pci_dev *pdev);
++
++/**
++ * intel_qrk_gpio_isr
++ *
++ * @param irq: IRQ number to be served
++ * @param dev_id: used to distinguish the device (for shared interrupts)
++ *
++ * Perform GPIO-specific ISR of the top-level GIP driver.
++ */
++irqreturn_t intel_qrk_gpio_isr(int irq, void *dev_id);
++
++/**
++ * intel_qrk_gpio_save_state
++ *
++ * Save GPIO register state for system-wide suspend events and mask out
++ * interrupts.
++ */
++void intel_qrk_gpio_save_state(void);
++
++/**
++ * intel_qrk_gpio_restore_state
++ *
++ * Restore GPIO register state for system-wide resume events and clear out
++ * spurious interrupts.
++ */
++void intel_qrk_gpio_restore_state(void);
++
++/**
++ * intel_qrk_i2c_probe
++ * @param pdev: Pointer to GIP PCI device
++ * @param drvdata: private driver data
++ * @param drvdata: GIP platform-specific settings
++ * @return 0 success < 0 failure
++ *
++ * Perform I2C-specific probing on behalf of the top-level GIP driver.
++ */
++int intel_qrk_i2c_probe(struct pci_dev *pdev,
++ struct dw_i2c_dev **drvdata,
++ struct intel_qrk_gip_pdata *pdata);
++
++/**
++ * intel_qrk_i2c_remove
++ * @param pdev: Pointer to GIP PCI device
++ * @param dev: Pointer to I2C private data
++ *
++ * Perform I2C-specific resource release on behalf of the top-level GIP driver.
++ */
++void intel_qrk_i2c_remove(struct pci_dev *pdev,
++ struct dw_i2c_dev *dev);
++
++#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
+--- /dev/null
++++ b/drivers/mfd/intel_qrk_gip_core.c
+@@ -0,0 +1,335 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark GIP (GPIO/I2C) PCI driver
++ *
++ * PCI glue logic for Quark GIP driver.
++ * Quark GIP is a single PCI function exporting a GPIO and an I2C device.
++ * The PCI driver performs the bus-dependent probe/release operations, and
++ * call into GPIO/I2C specific modules for handling the two diffrerent
++ * functionalities.
++ */
++
++#include <asm/qrk.h>
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/mfd/intel_qrk_gip_pdata.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include "intel_qrk_gip.h"
++
++static unsigned int enable_msi = 1;
++module_param(enable_msi, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
++
++static unsigned int i2c = 1;
++module_param(i2c, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(i2c, "Register I2C adapter");
++
++static unsigned int gpio = 1;
++module_param(gpio, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(gpio, "Register GPIO chip");
++
++/* GIP private data, supporting only a single instance of the device. */
++struct intel_qrk_gip_data {
++ struct pci_dev *pci_device;
++ struct dw_i2c_dev *i2c_drvdata;
++ struct intel_qrk_gip_pdata *pdata;
++};
++
++/**
++ * intel_qrk_gip_handler
++ *
++ * @param irq: IRQ number to be served
++ * @param dev_id: device private data
++ *
++ * Top-level interrupt handler for GIP driver.
++ * It calls into the appropriate sub-routines and gathers the return values.
++ */
++static irqreturn_t intel_qrk_gip_handler(int irq, void *dev_id)
++{
++ irqreturn_t ret_i2c = IRQ_NONE;
++ irqreturn_t ret_gpio = IRQ_NONE;
++ struct intel_qrk_gip_data *data = (struct intel_qrk_gip_data *)dev_id;
++
++ mask_pvm(data->pci_device);
++
++ if (likely(i2c)) {
++ /* Only I2C gets platform data */
++ ret_i2c = i2c_dw_isr(irq, data->i2c_drvdata);
++ }
++
++ if (likely(gpio)) {
++ ret_gpio = intel_qrk_gpio_isr(irq, NULL);
++ }
++
++ unmask_pvm(data->pci_device);
++
++ if (likely(IRQ_HANDLED == ret_i2c || IRQ_HANDLED == ret_gpio))
++ return IRQ_HANDLED;
++
++ /* Each sub-ISR routine returns either IRQ_HANDLED or IRQ_NONE. */
++ return IRQ_NONE;
++}
++
++static DEFINE_PCI_DEVICE_TABLE(intel_qrk_gip_ids) = {
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0934), },
++ { 0, }
++};
++MODULE_DEVICE_TABLE(pci, intel_qrk_gip_ids);
++
++#ifdef CONFIG_PM
++
++/**
++ * qrk_gip_suspend
++ *
++ * @param device: Pointer to device
++ * @return 0 success < 0 failure
++ *
++ * Prepare GIP for system-wide transition to sleep state.
++ * Save context, disable GPIO chip and I2C adapter, transition PCI device into
++ * low-power state.
++ */
++static int qrk_gip_suspend(struct device *dev)
++{
++ int err = 0;
++ struct intel_qrk_gip_data *data = NULL;
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ data = (struct intel_qrk_gip_data *)pci_get_drvdata(pdev);
++
++ i2c_dw_disable(data->i2c_drvdata);
++ intel_qrk_gpio_save_state();
++
++ err = pci_save_state(pdev);
++ if (err) {
++ dev_err(&pdev->dev, "pci_save_state failed\n");
++ return err;
++ }
++
++ err = pci_set_power_state(pdev, PCI_D3hot);
++ if (err) {
++ dev_err(&pdev->dev, "pci_set_power_state failed\n");
++ return err;
++ }
++
++ return 0;
++}
++
++/**
++ * qrk_gip_resume
++ *
++ * @param device: Pointer to device
++ * @return 0 success < 0 failure
++ *
++ * Prepare GIP for system-wide transition to fully active state.
++ * Set PCI device into full-power state, restore context, enable I2C adapter
++ * and GPIO chip.
++ */
++static int qrk_gip_resume(struct device *dev)
++{
++ int err = 0;
++ struct intel_qrk_gip_data *data = NULL;
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ data = (struct intel_qrk_gip_data *)pci_get_drvdata(pdev);
++
++ err = pci_set_power_state(pdev, PCI_D0);
++ if (err) {
++ dev_err(&pdev->dev, "pci_set_power_state() failed\n");
++ return err;
++ }
++
++ pci_restore_state(pdev);
++
++ intel_qrk_gpio_restore_state();
++ i2c_dw_init(data->i2c_drvdata);
++
++ return 0;
++}
++
++#else
++#define qrk_gip_suspend NULL
++#define qrk_gip_resume NULL
++#endif
++
++static const struct dev_pm_ops qrk_gip_pm_ops = {
++ .resume = qrk_gip_resume,
++ .suspend = qrk_gip_suspend,
++};
++
++/**
++ * intel_qrk_gip_probe
++ *
++ * @param pdev: Pointer to GIP PCI device
++ * @param id: GIP PCI Device ID
++ * @return 0 success < 0 failure
++ *
++ * GIP PCI driver probing. Calls into the appropriate probe routines for GPIO
++ * and I2C too.
++ */
++static int intel_qrk_gip_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ int retval = 0;
++ struct intel_qrk_gip_data *gip_drvdata = NULL;
++
++ retval = pci_enable_device(pdev);
++ if (retval)
++ return retval;
++
++ retval = pci_request_regions(pdev, "qrk-gip");
++ if (retval) {
++ dev_err(&pdev->dev, "error requesting PCI region\n");
++ goto err_pcidev_disable;
++ }
++
++ gip_drvdata = kzalloc(sizeof(struct intel_qrk_gip_data), GFP_KERNEL);
++ if (NULL == gip_drvdata) {
++ retval = -ENOMEM;
++ goto err_pciregions_release;
++ }
++ pci_set_drvdata(pdev, gip_drvdata);
++
++ gip_drvdata->pci_device = pdev;
++
++ /* Retrieve platform data if there is any */
++ if (*intel_qrk_gip_get_pdata) {
++ gip_drvdata->pdata = intel_qrk_gip_get_pdata();
++ }
++
++ if (gpio) {
++ retval = intel_qrk_gpio_probe(pdev);
++ if (retval)
++ goto err_release_drvdata;
++ }
++
++ if (i2c) {
++ retval = intel_qrk_i2c_probe(pdev,
++ (struct dw_i2c_dev **)&gip_drvdata->i2c_drvdata,
++ gip_drvdata->pdata);
++ if (retval)
++ goto err_release_drvdata;
++ }
++
++ if (enable_msi) {
++ pci_set_master(pdev);
++ retval = pci_enable_msi(pdev);
++ if (retval)
++ goto err_release_drvdata;
++ }
++
++ /*
++ * Request a shared IRQ.
++ * Since the dev_id cannot be NULL, it points to PCI device descriptor
++ * if I2C is not registered.
++ */
++ retval = request_irq(pdev->irq, intel_qrk_gip_handler, IRQF_SHARED,
++ "intel_qrk_gip", gip_drvdata);
++ if (retval) {
++ dev_err(&pdev->dev, "error requesting IRQ\n");
++ goto err;
++ }
++
++ return 0;
++
++err_release_drvdata:
++ pci_set_drvdata(pdev, NULL);
++ kfree(gip_drvdata);
++err:
++ if (enable_msi)
++ pci_disable_msi(pdev);
++err_pciregions_release:
++ pci_release_regions(pdev);
++err_pcidev_disable:
++ pci_disable_device(pdev);
++
++ return retval;
++}
++
++/**
++ * intel_qrk_gip_remove
++ *
++ * @param pdev: Pointer to GIP PCI device
++ *
++ * Release resources. Calls into GPIO/I2C dedicate routines too.
++ */
++static void intel_qrk_gip_remove(struct pci_dev *pdev)
++{
++ struct intel_qrk_gip_data *data = NULL;
++
++ data = (struct intel_qrk_gip_data *)pci_get_drvdata(pdev);
++
++ if (NULL == data) {
++ dev_err(&pdev->dev, "%s: failure getting driver data\n",
++ __func__);
++ return;
++ }
++
++ free_irq(pdev->irq, data);
++
++ if (enable_msi) {
++ pci_clear_master(pdev);
++ if (pci_dev_msi_enabled(pdev))
++ pci_disable_msi(pdev);
++ }
++
++ if (i2c)
++ intel_qrk_i2c_remove(pdev, data->i2c_drvdata);
++
++ if (gpio)
++ intel_qrk_gpio_remove(pdev);
++
++ pci_set_drvdata(pdev, NULL);
++ kfree(data);
++
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++}
++
++static struct pci_driver intel_qrk_gip_driver = {
++ .name = "intel_qrk_gip",
++ .id_table = intel_qrk_gip_ids,
++ .probe = intel_qrk_gip_probe,
++ .remove = intel_qrk_gip_remove,
++ .driver = {
++ .pm = &qrk_gip_pm_ops,
++ },
++};
++
++static int intel_qrk_gip_init(void)
++{
++ return pci_register_driver(&intel_qrk_gip_driver);
++}
++
++static void intel_qrk_gip_exit(void)
++{
++ pci_unregister_driver(&intel_qrk_gip_driver);
++}
++
++module_init(intel_qrk_gip_init);
++module_exit(intel_qrk_gip_exit);
++
++MODULE_AUTHOR("Intel Corporation");
++MODULE_DESCRIPTION("Quark GIP driver");
++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
+--- /dev/null
++++ b/drivers/mfd/intel_qrk_gip_gpio.c
+@@ -0,0 +1,659 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark GIP (GPIO/I2C) - GPIO-specific PCI and core driver
++ *
++ * PCI glue logic and core driver for Quark GIP/GPIO.
++ * The GIP GPIO device is the DesignWare GPIO. This file defines the PCI glue
++ * for this driver and as well as the core logic for the device.
++ * Please note only a single instance of the GPIO device is supported.
++ * The default number of GPIO is 8, all interrupt-capable.
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/uio_driver.h>
++#include "intel_qrk_gip.h"
++
++static void qrk_gpio_restrict_release(struct device *dev) {}
++static struct platform_device qrk_gpio_restrict_pdev =
++{
++ .name = "qrk-gpio-restrict-sc",
++ .dev.release = qrk_gpio_restrict_release,
++};
++struct uio_info *info;
++
++/* The base GPIO number under GPIOLIB framework */
++#define INTEL_QRK_GIP_GPIO_BASE 8
++
++/* The default number of South-Cluster GPIO on Quark. */
++#define INTEL_QRK_GIP_NGPIO 8
++
++/*
++ * The default base IRQ for searching and allocating the range of GPIO IRQ
++ * descriptors.
++ */
++#define INTEL_QRK_GIP_GPIO_IRQBASE 56
++
++/* The GPIO private data. */
++static struct gpio_chip *gc;
++static struct irq_chip_generic *igc;
++static void __iomem *reg_base;
++static spinlock_t lock;
++static int irq_base;
++static unsigned int n_gpio = INTEL_QRK_GIP_NGPIO;
++static unsigned int gpio_irqbase = INTEL_QRK_GIP_GPIO_IRQBASE;
++
++/* Store GPIO context across system-wide suspend/resume transitions */
++static struct gpio_saved_regs {
++ u32 data;
++ u32 dir;
++ u32 int_en;
++ u32 int_mask;
++ u32 int_type;
++ u32 int_pol;
++ u32 int_deb;
++} saved_regs;
++
++/* PortA registers set. Note other ports are unused */
++#define PORTA_DATA 0x00 /* Data */
++#define PORTA_DIR 0x04 /* Direction */
++#define PORTA_INT_EN 0x30 /* Interrupt enable */
++#define PORTA_INT_MASK 0x34 /* Interrupt mask */
++#define PORTA_INT_TYPE_LEVEL 0x38 /* Interrupt level*/
++#define PORTA_INT_POLARITY 0x3c /* Interrupt polarity */
++#define PORTA_INT_STATUS 0x40 /* Interrupt status */
++#define PORTA_INT_RAW_STATUS 0x44 /* Interrupt raw status */
++#define PORTA_DEBOUNCE 0x48 /* Debounce enable */
++#define PORTA_INT_EOI 0x4c /* Clear interrupt */
++#define PORTA_EXT 0x50 /* External */
++
++module_param(n_gpio, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(n_gpio, "Number of GPIO");
++
++module_param(gpio_irqbase, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(gpio_irqbase, "Base IRQ for GPIO range");
++
++/**
++ * intel_qrk_gpio_get
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @return 0 if GPIO is deasserted, 1 if GPIO is asserted
++ *
++ * Read back the value of a GPIO.
++ */
++static int intel_qrk_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ void __iomem *reg_ext = reg_base + PORTA_EXT;
++ u32 val_ext = ioread32(reg_ext);
++
++ val_ext &= BIT(offset % 32);
++ return (val_ext > 0);
++}
++
++/**
++ * intel_qrk_gpio_set
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ *
++ * Set value of a GPIO.
++ */
++static void intel_qrk_gpio_set(struct gpio_chip *chip, unsigned offset,
++ int value)
++{
++ void __iomem *reg_data = reg_base + PORTA_DATA;
++ u32 val_data = 0;
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_data = ioread32(reg_data);
++ if (value)
++ iowrite32(val_data | BIT(offset % 32), reg_data);
++ else
++ iowrite32(val_data & ~BIT(offset % 32), reg_data);
++
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_direction_input
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @return always 0 (success)
++ *
++ * Set direction of a GPIO as input.
++ */
++static int intel_qrk_gpio_direction_input(struct gpio_chip *chip,
++ unsigned offset)
++{
++ u32 val_dir = 0;
++ void __iomem *reg_dir = reg_base + PORTA_DIR;
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_dir = ioread32(reg_dir);
++ iowrite32(val_dir & ~BIT(offset % 32), reg_dir);
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return 0;
++}
++
++/**
++ * intel_qrk_gpio_direction_output
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @param value: value to be driven to the GPIO
++ * @return always 0 (success)
++ *
++ * Set the default value of a GPIO, and then set direction as output.
++ */
++static int intel_qrk_gpio_direction_output(struct gpio_chip *chip,
++ unsigned offset, int value)
++{
++ u32 val_dir = 0;
++ void __iomem *reg_dir = reg_base + PORTA_DIR;
++ unsigned long flags = 0;
++
++ /* Ensure glitch-free operation. */
++ intel_qrk_gpio_set(chip, offset, value);
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_dir = ioread32(reg_dir);
++ iowrite32(val_dir | BIT(offset % 32), reg_dir);
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return 0;
++}
++
++/**
++ * intel_qrk_gpio_set_debounce
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @param debounce: 1 to enable, 0 to disable
++ * @return always 0 (success)
++ *
++ * Enable/disable interrupt debounce logic for a GPIO.
++ */
++static int intel_qrk_gpio_set_debounce(struct gpio_chip *chip,
++ unsigned offset, unsigned debounce)
++{
++ u32 val_deb = 0;
++ void __iomem *reg_deb = reg_base + PORTA_DEBOUNCE;
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_deb = ioread32(reg_deb);
++ if (debounce)
++ iowrite32(val_deb | BIT(offset % 32), reg_deb);
++ else
++ iowrite32(val_deb & ~BIT(offset % 32), reg_deb);
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return 0;
++}
++
++/**
++ * intel_qrk_gpio_irq_type
++ * @param irq_data: Pointer to information about the IRQ
++ * @param type: set the triggering type of the interrupt
++ * @return always 0 (success)
++ *
++ * Set interrupt triggering type for a GPIO.
++ */
++static int intel_qrk_gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ int ret = 0;
++ unsigned long flags = 0;
++ void __iomem *reg_level = reg_base + PORTA_INT_TYPE_LEVEL;
++ void __iomem *reg_pol = reg_base + PORTA_INT_POLARITY;
++ u32 val_level = 0;
++ u32 val_pol = 0;
++ u32 gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return -EFAULT;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_level = ioread32(reg_level);
++ val_pol = ioread32(reg_pol);
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ iowrite32(val_level | BIT(gpio % 32), reg_level);
++ iowrite32(val_pol | BIT(gpio % 32), reg_pol);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ iowrite32(val_level | BIT(gpio % 32), reg_level);
++ iowrite32(val_pol & ~BIT(gpio % 32), reg_pol);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ iowrite32(val_level & ~BIT(gpio % 32), reg_level);
++ iowrite32(val_pol | BIT(gpio % 32), reg_pol);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ iowrite32(val_level & ~BIT(gpio % 32), reg_level);
++ iowrite32(val_pol & ~BIT(gpio % 32), reg_pol);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return ret;
++}
++
++/**
++ * intel_qrk_gpio_irq_unmask
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Unmask interrupts for a GPIO.
++ */
++static void intel_qrk_gpio_irq_unmask(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_mask = reg_base + PORTA_INT_MASK;
++ u32 val_mask = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_mask = ioread32(reg_mask);
++ iowrite32(val_mask | BIT(gpio % 32), reg_mask);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_irq_mask
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Mask interrupts for a GPIO.
++ */
++static void intel_qrk_gpio_irq_mask(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_mask = reg_base + PORTA_INT_MASK;
++ u32 val_mask = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_mask = ioread32(reg_mask);
++ iowrite32(val_mask & ~BIT(gpio % 32), reg_mask);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_irq_enable
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Enable interrupts for a GPIO.
++ */
++static void intel_qrk_gpio_irq_enable(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_inte = reg_base + PORTA_INT_EN;
++ u32 val_inte = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_inte = ioread32(reg_inte);
++ iowrite32(val_inte | BIT(gpio % 32), reg_inte);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_irq_disable
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Disable interrupts for a GPIO.
++ */
++static void intel_qrk_gpio_irq_disable(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_inte = reg_base + PORTA_INT_EN;
++ u32 val_inte = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_inte = ioread32(reg_inte);
++ iowrite32(val_inte & ~BIT(gpio % 32), reg_inte);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_to_irq
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @return IRQ associated to GPIO
++ *
++ * Compute the IRQ number based on the GPIO.
++ */
++static int intel_qrk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ return irq_base + offset;
++}
++
++/**
++ * intel_qrk_gpio_isr
++ * @param irq: IRQ number
++ * @param dev_id: cookie used to tell what instance of the driver the interrupt
++ * belongs to
++ * @return IRQ_HANDLED if interrupt served, IRQ_NONE if no interrupt pending
++ *
++ * Interrupt Service Routine for GPIO. Identify which GPIOs (if any) is pending
++ * for interrupt to be served, acknowledge the interrupt and serve it.
++ */
++irqreturn_t intel_qrk_gpio_isr(int irq, void *dev_id)
++{
++ irqreturn_t ret = IRQ_NONE;
++ u32 pending = 0, gpio = 0;
++ void __iomem *reg_pending = reg_base + PORTA_INT_STATUS;
++ void __iomem *reg_eoi = reg_base + PORTA_INT_EOI;
++
++ /* Which pin (if any) triggered the interrupt */
++ while ((pending = ioread32(reg_pending))) {
++ /*
++ * Acknowledge all the asserted GPIO interrupt lines before
++ * serving them, so that we don't lose an edge.
++ * This has only effect on edge-triggered interrupts.
++ */
++ iowrite32(pending, reg_eoi);
++
++ /* Serve each asserted interrupt */
++ do {
++ gpio = __ffs(pending);
++ generic_handle_irq(
++ gpio_to_irq(INTEL_QRK_GIP_GPIO_BASE + gpio));
++ pending &= ~BIT(gpio);
++ ret = IRQ_HANDLED;
++ } while(pending);
++ }
++
++ return ret;
++}
++
++/**
++ * intel_qrk_gpio_save_state
++ *
++ * Save GPIO register state for system-wide suspend events and mask out
++ * interrupts.
++ */
++void intel_qrk_gpio_save_state(void)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ saved_regs.int_mask = ioread32(reg_base + PORTA_INT_MASK);
++ saved_regs.int_en = ioread32(reg_base + PORTA_INT_EN);
++ saved_regs.int_deb = ioread32(reg_base + PORTA_DEBOUNCE);
++ saved_regs.int_pol = ioread32(reg_base + PORTA_INT_POLARITY);
++ saved_regs.int_type = ioread32(reg_base + PORTA_INT_TYPE_LEVEL);
++ saved_regs.dir = ioread32(reg_base + PORTA_DIR);
++ saved_regs.data = ioread32(reg_base + PORTA_DATA);
++
++ /* Mask out interrupts */
++ iowrite32(0xffffffff, reg_base + PORTA_INT_MASK);
++
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_restore_state
++ *
++ * Restore GPIO register state for system-wide resume events and clear out
++ * spurious interrupts.
++ */
++void intel_qrk_gpio_restore_state(void)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ iowrite32(saved_regs.data, reg_base + PORTA_DATA);
++ iowrite32(saved_regs.dir, reg_base + PORTA_DIR);
++ iowrite32(saved_regs.int_type, reg_base + PORTA_INT_TYPE_LEVEL);
++ iowrite32(saved_regs.int_pol, reg_base + PORTA_INT_POLARITY);
++ iowrite32(saved_regs.int_deb, reg_base + PORTA_DEBOUNCE);
++ iowrite32(saved_regs.int_en, reg_base + PORTA_INT_EN);
++ iowrite32(saved_regs.int_mask, reg_base + PORTA_INT_MASK);
++
++ /* Clear out spurious interrupts */
++ iowrite32(0xffffffff, reg_base + PORTA_INT_EOI);
++
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_qrk_gpio_probe
++ * @param pdev: Pointer to GIP PCI device
++ * @return 0 success < 0 failure
++ *
++ * Perform GPIO-specific probing on behalf of the top-level GIP driver.
++ * Initiate the GPIO device.
++ */
++int intel_qrk_gpio_probe(struct pci_dev *pdev)
++{
++ int retval = 0;
++ resource_size_t start = 0, len = 0;
++
++ /* Get UIO memory */
++ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ /* Determine the address of the GPIO area */
++ start = pci_resource_start(pdev, GIP_GPIO_BAR);
++ len = pci_resource_len(pdev, GIP_GPIO_BAR);
++ if (!start || len == 0) {
++ dev_err(&pdev->dev, "bar%d not set\n", GIP_GPIO_BAR);
++ retval = -ENODEV;
++ goto exit;
++ }
++
++ reg_base = ioremap_nocache(start, len);
++ if (NULL == reg_base) {
++ dev_err(&pdev->dev, "I/O memory remapping failed\n");
++ retval = -EFAULT;
++ goto exit;
++ }
++
++ memset(&saved_regs, 0x0, sizeof(saved_regs));
++
++ gc = kzalloc(sizeof(struct gpio_chip), GFP_KERNEL);
++ if (!gc) {
++ retval = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ if (n_gpio == 0 || n_gpio > INTEL_QRK_GIP_NGPIO) {
++ dev_err(&pdev->dev, "n_gpio outside range [1,%d]\n",
++ INTEL_QRK_GIP_NGPIO);
++ retval = -EINVAL;
++ goto err_free_gpiochip;
++ }
++
++ gc->label = "intel_qrk_gip_gpio";
++ gc->owner = THIS_MODULE;
++ gc->direction_input = intel_qrk_gpio_direction_input;
++ gc->direction_output = intel_qrk_gpio_direction_output;
++ gc->get = intel_qrk_gpio_get;
++ gc->set = intel_qrk_gpio_set;
++ gc->set_debounce = intel_qrk_gpio_set_debounce;
++ gc->to_irq = intel_qrk_gpio_to_irq;
++ gc->base = INTEL_QRK_GIP_GPIO_BASE;
++ gc->ngpio = n_gpio;
++ gc->can_sleep = 0;
++ retval = gpiochip_add(gc);
++ if (retval) {
++ dev_err(&pdev->dev, "failure adding GPIO chip\n");
++ goto err_free_gpiochip;
++ }
++
++ spin_lock_init(&lock);
++
++ /*
++ * Allocate a range of IRQ descriptor for the available GPIO.
++ * IRQs are allocated dynamically.
++ */
++ irq_base = irq_alloc_descs(-1, gpio_irqbase, n_gpio, NUMA_NO_NODE);
++ if (irq_base < 0) {
++ dev_err(&pdev->dev, "failure adding GPIO IRQ descriptors\n");
++ goto err_remove_gpiochip;
++ }
++
++ retval = platform_device_register(&qrk_gpio_restrict_pdev);
++ if (retval < 0){
++ goto err_free_irq_descs;
++ }
++
++ igc = irq_alloc_generic_chip("intel_qrk_gip_gpio", 1, irq_base,
++ reg_base, handle_simple_irq);
++ if (NULL == igc) {
++ retval = -ENOMEM;
++ goto err_free_irq_descs;
++ }
++
++ /* UIO */
++ info->mem[0].addr = start;
++ info->mem[0].internal_addr = reg_base;
++ info->mem[0].size = len;
++ info->mem[0].memtype = UIO_MEM_PHYS;
++ info->mem[0].name = "gpio_regs";
++ info->name = "gpio uio";
++ info->version = "0.0.1";
++
++ if (uio_register_device(&pdev->dev, info))
++ goto err_free_irq_descs;
++
++ pr_info("%s UIO addr 0x%08x internal_addr 0x%08x size %lu memtype %d\n",
++ __func__, (unsigned int)info->mem[0].addr,
++ (unsigned int)info->mem[0].internal_addr, info->mem[0].size,
++ info->mem[0].memtype);
++ igc->chip_types->chip.irq_mask = intel_qrk_gpio_irq_mask;
++ igc->chip_types->chip.irq_unmask = intel_qrk_gpio_irq_unmask;
++ igc->chip_types->chip.irq_set_type = intel_qrk_gpio_irq_type;
++ igc->chip_types->chip.irq_enable = intel_qrk_gpio_irq_enable;
++ igc->chip_types->chip.irq_disable = intel_qrk_gpio_irq_disable;
++
++ irq_setup_generic_chip(igc, IRQ_MSK(n_gpio), IRQ_GC_INIT_MASK_CACHE,
++ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
++
++ return 0;
++
++err_free_irq_descs:
++ irq_free_descs(irq_base, n_gpio);
++err_remove_gpiochip:
++ if (0 != gpiochip_remove(gc))
++ dev_err(&pdev->dev, "failed removing gpio_chip\n");
++err_free_gpiochip:
++ kfree(gc);
++err_iounmap:
++ iounmap(reg_base);
++exit:
++ if (info != NULL)
++ kfree(info);
++ return retval;
++}
++
++/**
++ * intel_qrk_gpio_remove
++ * @param pdev: Pointer to GIP PCI device
++ *
++ * Perform GPIO-specific resource release on behalf of the top-level GIP
++ * driver.
++ */
++void intel_qrk_gpio_remove(struct pci_dev *pdev)
++{
++ if (NULL == igc) {
++ dev_err(&pdev->dev, "null pointer to irq_generic_chip\n");
++ return;
++ }
++ if (NULL == gc) {
++ dev_err(&pdev->dev, "null pointer to gpio_chip\n");
++ return;
++ }
++
++ /* Tear down IRQ descriptors */
++ irq_remove_generic_chip(igc, IRQ_MSK(n_gpio), 0,
++ IRQ_NOREQUEST | IRQ_NOPROBE);
++ kfree(igc);
++ irq_free_descs(irq_base, n_gpio);
++
++ platform_device_unregister(&qrk_gpio_restrict_pdev);
++
++ /* Release GPIO chip */
++ if (0 != gpiochip_remove(gc))
++ dev_err(&pdev->dev, "failed removing gpio_chip\n");
++
++
++ if (info != NULL){
++ uio_unregister_device(info);
++ kfree(info);
++ }
++
++ kfree(gc);
++ iounmap(reg_base);
++}
+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
+--- /dev/null
++++ b/drivers/mfd/intel_qrk_gip_i2c.c
+@@ -0,0 +1,248 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark GIP (GPIO/I2C) - I2C-specific PCI driver
++ *
++ * PCI glue logic for Quark GIP/I2C.
++ * The GIP I2C device is the DesignWare I2C. This file defines the PCI glue
++ * for this driver and is heavily based on
++ * on drivers/i2c/busses/i2c-designware-pcidrv.c. Also, it relies on
++ * drivers/i2c/busses/i2c-designware-core.c for the core logic.
++ * Please note only a single instance of the I2C device is supported.
++ */
++
++#include <linux/errno.h>
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include "intel_qrk_gip.h"
++
++enum dw_pci_ctl_id_t {
++ quark_0,
++};
++
++/*
++ * By default, driver operates in fast mode (400kHz).
++ *
++ * Standard mode operation (100kHz) can be forced via, in order of priority:
++ * 1. setting the following i2c_std_mode module parameter to 1
++ * 2. setting the platform data i2c_std_mode parameter to 1
++ *
++ * Note in both cases, setting i2c_std_mode to 0 means forcing fast mode
++ * operation.
++ */
++static unsigned int i2c_std_mode = -1;
++module_param(i2c_std_mode, uint, S_IRUSR);
++MODULE_PARM_DESC(i2c_std_mode, "Set to 1 to force I2C standard mode");
++
++#define INTEL_QRK_STD_CFG (DW_IC_CON_MASTER | \
++ DW_IC_CON_SLAVE_DISABLE | \
++ DW_IC_CON_RESTART_EN)
++
++static struct dw_pci_controller qrk_gip_i2c_controller = {
++ .bus_num = 0,
++ .bus_cfg = INTEL_QRK_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 16,
++ .rx_fifo_depth = 16,
++ .clk_khz =
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
++ 14000,
++#else
++ 33000,
++#endif
++ .explicit_stop = 1,
++};
++
++static struct i2c_algorithm i2c_dw_algo = {
++ .master_xfer = i2c_dw_xfer,
++ .functionality = i2c_dw_func,
++};
++
++/**
++ * i2c_dw_get_clk_rate_khz
++ * @param dev: Pointer to I2C device private data
++ * @return clock rate in kHz
++ *
++ * Ancillary function returning the frequency of the clock supplied to the
++ * interface.
++ */
++static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
++{
++ return dev->controller->clk_khz;
++}
++
++/**
++ * intel_qrk_i2c_probe
++ * @param pdev: Pointer to GIP PCI device
++ * @param drvdata: private driver data
++ * @return 0 success < 0 failure
++ *
++ * Perform I2C-specific probing on behalf of the top-level GIP driver.
++ * Also call into I2C core driver routines for initiating the device.
++ */
++int intel_qrk_i2c_probe(struct pci_dev *pdev,
++ struct dw_i2c_dev **drvdata,
++ struct intel_qrk_gip_pdata *pdata)
++{
++ int retval = 0;
++ resource_size_t start = 0, len = 0;
++ struct dw_i2c_dev *dev = NULL;
++ struct i2c_adapter *adap = NULL;
++ void __iomem *reg_base = NULL;
++ struct dw_pci_controller *controller = NULL;
++ int std_mode = -1;
++
++ controller = &qrk_gip_i2c_controller;
++
++ /* Quark default configuration is fast mode, unless otherwise forced */
++ if (-1 != i2c_std_mode) {
++ switch (i2c_std_mode) {
++ case 0:
++ case 1:
++ std_mode = i2c_std_mode;
++ break;
++ default:
++ dev_err(&pdev->dev, "invalid i2c_std_mode param val %d."
++ " Using driver default\n", i2c_std_mode);
++ break;
++ }
++ } else if (pdata) {
++ switch (pdata->i2c_std_mode) {
++ case 0:
++ case 1:
++ std_mode = pdata->i2c_std_mode;
++ break;
++ default:
++ dev_err(&pdev->dev, "invalid i2c_std_mode pdata val %d."
++ " Usign driver default\n", pdata->i2c_std_mode);
++ break;
++ }
++ }
++ if (-1 != std_mode) {
++ if (0 == std_mode) {
++ controller->bus_cfg |= DW_IC_CON_SPEED_FAST;
++ controller->bus_cfg &= ~DW_IC_CON_SPEED_STD;
++ } else {
++ controller->bus_cfg &= ~DW_IC_CON_SPEED_FAST;
++ controller->bus_cfg |= DW_IC_CON_SPEED_STD;
++ }
++ dev_info(&pdev->dev, "i2c speed set to %skHz\n",
++ std_mode ? "100" : "400");
++ }
++
++ /* Determine the address of the I2C area */
++ start = pci_resource_start(pdev, GIP_I2C_BAR);
++ len = pci_resource_len(pdev, GIP_I2C_BAR);
++ if (!start || len == 0) {
++ dev_err(&pdev->dev, "bar%d not set\n", GIP_I2C_BAR);
++ retval = -ENODEV;
++ goto err;
++ }
++
++ reg_base = ioremap_nocache(start, len);
++ if (!reg_base) {
++ dev_err(&pdev->dev, "I/O memory remapping failed\n");
++ retval = -ENOMEM;
++ goto err;
++ }
++
++ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
++ if (!dev) {
++ retval = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ init_completion(&dev->cmd_complete);
++ mutex_init(&dev->lock);
++ dev->clk = NULL;
++ dev->controller = controller;
++ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
++ dev->base = reg_base;
++ dev->dev = get_device(&pdev->dev);
++ dev->functionality =
++ I2C_FUNC_I2C |
++ I2C_FUNC_10BIT_ADDR |
++ I2C_FUNC_SMBUS_BYTE |
++ I2C_FUNC_SMBUS_BYTE_DATA |
++ I2C_FUNC_SMBUS_WORD_DATA |
++ I2C_FUNC_SMBUS_I2C_BLOCK;
++ dev->master_cfg = controller->bus_cfg;
++
++ *drvdata = dev;
++
++ dev->tx_fifo_depth = controller->tx_fifo_depth;
++ dev->rx_fifo_depth = controller->rx_fifo_depth;
++ dev->explicit_stop = controller->explicit_stop;
++ retval = i2c_dw_init(dev);
++ if (retval)
++ goto err_release_drvdata;
++
++ adap = &dev->adapter;
++ i2c_set_adapdata(adap, dev);
++ adap->owner = THIS_MODULE;
++ adap->class = 0;
++ adap->algo = &i2c_dw_algo;
++ adap->dev.parent = &pdev->dev;
++ adap->nr = controller->bus_num;
++ snprintf(adap->name, sizeof(adap->name), "intel_qrk_gip_i2c");
++
++ i2c_dw_disable_int(dev);
++ i2c_dw_clear_int(dev);
++ retval = i2c_add_numbered_adapter(adap);
++ if (retval) {
++ dev_err(&pdev->dev, "failure adding I2C adapter\n");
++ goto err_release_drvdata;
++ }
++
++ return 0;
++
++err_release_drvdata:
++ put_device(&pdev->dev);
++ kfree(dev);
++err_iounmap:
++ iounmap(reg_base);
++err:
++ return retval;
++}
++
++/**
++ * intel_qrk_i2c_remove
++ * @param pdev: Pointer to GIP PCI device
++ * @param dev: Pointer to I2C private data
++ *
++ * Perform I2C-specific resource release on behalf of the top-level GIP driver.
++ */
++void intel_qrk_i2c_remove(struct pci_dev *pdev,
++ struct dw_i2c_dev *dev)
++{
++
++ if (NULL == dev) {
++ dev_err(&pdev->dev, "%s: failure getting driver data\n",
++ __func__);
++ return;
++ }
++
++ i2c_dw_disable(dev);
++ i2c_del_adapter(&dev->adapter);
++ iounmap(dev->base);
++
++ kfree(dev);
++}
+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
+--- /dev/null
++++ b/drivers/mfd/intel_qrk_gip_pdata.c
+@@ -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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++#include <linux/module.h>
++#include <linux/mfd/intel_qrk_gip_pdata.h>
++
++struct intel_qrk_gip_pdata *(*intel_qrk_gip_get_pdata)(void) = NULL;
++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
+--- /dev/null
++++ b/drivers/mfd/intel_qrk_gip_test.c
+@@ -0,0 +1,1131 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Quark GIP (GPIO/I2C) Test module
++ *
++ * Quark GIP + North-Cluster GPIO test module.
++ */
++
++#include <asm/tsc.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++#include <linux/workqueue.h>
++
++#define DRIVER_NAME "intel_qrk_gip_test"
++
++/**************************** Exported to LISA *******************************/
++
++/*
++ * Internally-used ioctl code. At the moment it is not reserved by any mainline
++ * driver.
++ */
++#define GIP_TEST_IOCTL_CODE 0xE0
++
++/*
++ * Integers for ioctl operation.
++ */
++#define IOCTL_QRK_GPIO_11 _IO(GIP_TEST_IOCTL_CODE, 0x00)
++#define IOCTL_QRK_GPIO_11_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x01)
++#define IOCTL_QRK_GPIO_12 _IO(GIP_TEST_IOCTL_CODE, 0x02)
++#define IOCTL_QRK_GPIO_12_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x03)
++#define IOCTL_QRK_GPIO_13 _IO(GIP_TEST_IOCTL_CODE, 0x04)
++#define IOCTL_QRK_GPIO_13_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x05)
++#define IOCTL_QRK_GPIO_14 _IO(GIP_TEST_IOCTL_CODE, 0x06)
++#define IOCTL_QRK_GPIO_14_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x07)
++#define IOCTL_QRK_GPIO_15 _IO(GIP_TEST_IOCTL_CODE, 0x08)
++#define IOCTL_QRK_GPIO_15_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x09)
++#define IOCTL_QRK_GPIO_16 _IO(GIP_TEST_IOCTL_CODE, 0x0A)
++#define IOCTL_QRK_GPIO_16_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0B)
++#define IOCTL_QRK_GPIO_17 _IO(GIP_TEST_IOCTL_CODE, 0x0C)
++#define IOCTL_QRK_GPIO_17_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0D)
++#define IOCTL_QRK_GPIO_19 _IO(GIP_TEST_IOCTL_CODE, 0x0E)
++#define IOCTL_QRK_GPIO_19_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0F)
++#define IOCTL_QRK_GPIO_20 _IO(GIP_TEST_IOCTL_CODE, 0x10)
++#define IOCTL_QRK_GPIO_20_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x11)
++#define IOCTL_QRK_GPIO_21 _IO(GIP_TEST_IOCTL_CODE, 0x12)
++#define IOCTL_QRK_GPIO_21_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x13)
++#define IOCTL_QRK_GPIO_24 _IO(GIP_TEST_IOCTL_CODE, 0x14)
++#define IOCTL_QRK_GPIO_26 _IO(GIP_TEST_IOCTL_CODE, 0x15)
++#define IOCTL_QRK_GPIO_26_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x16)
++/* Exercise callbacks for S0/S3 power-state transitions and vice-versa */
++#define IOCTL_QRK_GIP_SYSTEM_SUSPEND _IO(GIP_TEST_IOCTL_CODE, 0x17)
++#define IOCTL_QRK_GIP_SYSTEM_RESUME _IO(GIP_TEST_IOCTL_CODE, 0x18)
++#define IOCTL_QRK_GPIO_NMI_ENABLE _IO(GIP_TEST_IOCTL_CODE, 0x19)
++#define IOCTL_QRK_GPIO_NMI_DISABLE _IO(GIP_TEST_IOCTL_CODE, 0x1A)
++
++#define GPIO_INT_EDGE_POS_LABEL "gpio-edge-pos"
++#define GPIO_INT_EDGE_NEG_LABEL "gpio-edge-neg"
++#define GPIO_INT_LEVEL_HIGH_LABEL "gpio-level-hi"
++#define GPIO_INT_LEVEL_LOW_LABEL "gpio-level-lo"
++#define GPIO_INT_BASIC_LABEL "gpio-edge-pos-basic"
++#define GPIO_PM_TEST_IRQ_LABEL "gpio_pm_test_irq"
++
++/*
++ * Board GPIO numbers.
++ * Mapping between the North/South cluster GPIO and GPIOLIB IDs.
++ */
++#define SUT_GPIO_NC_0 0x00
++#define SUT_GPIO_NC_1 0x01
++#define SUT_GPIO_NC_2 0x02
++#define SUT_GPIO_NC_7 0x07
++#define SUT_GPIO_SC_0 0x08
++#define SUT_GPIO_SC_1 0x09
++#define SUT_GPIO_SC_6 0x0E
++#define SUT_GPIO_SC_7 0x0F
++
++/*
++ * Bitbanged SPI bus numbers.
++ */
++#define GPIO_NC_BITBANG_SPI_BUS 0x0
++#define GPIO_SC_BITBANG_SPI_BUS 0x1
++
++/*****************************************************************************/
++
++/**
++ * struct intel_qrk_gip_dev
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_qrk_gip_test_dev {
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++};
++
++static struct intel_qrk_gip_test_dev gip_test_dev;
++static struct class *gip_test_class;
++static DEFINE_MUTEX(gip_test_mutex);
++static int gip_test_major;
++
++/*
++ * Level-triggered interrupt variables
++ */
++/* Level-triggered GPIO workqueue */
++static struct delayed_work work;
++/* Level-triggered interrupt counter */
++static unsigned int level_int_count;
++/* By default, a level-triggered interrupt is a low-level triggered */
++static int level_high_triggered = 0;
++
++/*
++ * Interrupt performance metrics variables and parameters
++ */
++/* How many captures */
++#define INT_PERF_TEST_CAPTURES 10000
++/* Timestamp for latency test interrupt handler */
++static cycles_t perf_t1;
++/* Captures to be returned to user space */
++static cycles_t deltas[INT_PERF_TEST_CAPTURES];
++/* Couldn't find the actual define for this */
++#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
++
++static irqreturn_t gpio_pm_test_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_latency_handler(int irq, void *dev_id)
++{
++ /* t0 */
++ perf_t1 = get_cycles();
++
++ gpio_set_value(SUT_GPIO_SC_0, 0);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_basic_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_pos_edge_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_neg_edge_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_level_handler(int irq, void *dev_id)
++{
++ /* Untrigger the interrupt */
++ gpio_set_value(SUT_GPIO_SC_7, level_high_triggered ? 0 : 1);
++
++ level_int_count ++;
++ if (level_int_count < 1000) {
++ /* Next task due in a jiffy */
++ schedule_delayed_work(&work, 1);
++ } else if (level_int_count == 1000){
++ /* OK */
++ } else {
++ /*
++ * We may get spurious interrupts. This because the TE requires
++ * some time to drive the actual value to the GPIO.
++ */
++ pr_info("Spurious interrupt\n");
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void gpio_level_drive(struct work_struct *work)
++{
++ /* TE to trigger the interrupt */
++ gpio_set_value(SUT_GPIO_SC_7, level_high_triggered ? 1 : 0);
++}
++
++/**
++ * gpio_sc_level_int
++ *
++ * Request level triggered IRQ for SUT_GPIO_SC_6 and register
++ * SUT_GPIO_SC_7 as output GPIO.
++ * If positive equals to 0, the IRQ is high-level triggered.
++ * Otherwise, low-level triggered.
++ * Mask the IRQ if requested.
++ */
++static int gpio_sc_level_int(int positive, int masking)
++{
++ int ret = 0;
++ int irq = -1;
++
++ unsigned long out_init_val =
++ (positive ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
++
++ level_high_triggered = positive;
++
++ /* Initialise workqueue task */
++ INIT_DELAYED_WORK(&work, gpio_level_drive);
++
++ if (!gpio_is_valid(SUT_GPIO_SC_6)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_6);
++ ret = -1;
++ goto fail;
++ }
++ if (!gpio_is_valid(SUT_GPIO_SC_7)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_7);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(SUT_GPIO_SC_6, GPIOF_IN, "gpio_hi_level");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_6, ret);
++ goto fail;
++ }
++ ret = gpio_request_one(SUT_GPIO_SC_7, out_init_val, "gpio_output");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_7, ret);
++ goto fail_release_first_gpio;
++ }
++
++ irq = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++
++ if (0 != (ret = request_irq(irq, gpio_level_handler,
++ positive ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW,
++ positive ? GPIO_INT_LEVEL_HIGH_LABEL : GPIO_INT_LEVEL_LOW_LABEL,
++ NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++
++ level_int_count = 0;
++
++ pr_info("Registered output gpio%d and IRQ for gpio%d\n", SUT_GPIO_SC_7,
++ SUT_GPIO_SC_6);
++
++ if (masking) {
++ disable_irq(gpio_to_irq(SUT_GPIO_SC_6));
++ pr_info("Masked gpio%d IRQ\n", SUT_GPIO_SC_6);
++ }
++
++ /*
++ * Submit task to workqueue to drive the external Test Equipment.
++ * Note the task is delayed long enough to have Aarvark already set up.
++ * This because Aardvark has to ignore the initial glitches during the
++ * previous GPIO setup phase.
++ */
++ schedule_delayed_work(&work, 20 * HZ);
++
++ return 0;
++
++fail_release_second_gpio:
++ gpio_free(SUT_GPIO_SC_7);
++fail_release_first_gpio:
++ gpio_free(SUT_GPIO_SC_6);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_level_int_teardown
++ *
++ * Release resources reserved by gpio_sc_level_int().
++ */
++static int gpio_sc_level_int_teardown(void)
++{
++ int irq = -1;
++
++ if (0 != cancel_delayed_work_sync(&work))
++ pr_warn("delayed work was still pending\n");
++
++ irq = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ /* Make sure no handler is still running by this time */
++ mdelay(20);
++
++ gpio_free(SUT_GPIO_SC_7);
++ gpio_free(SUT_GPIO_SC_6);
++
++ return 0;
++}
++
++/*
++ * gpio_sc_interrupt_perf
++ *
++ * Performs a basic GPIO interrupt latency test by timestamping delta between
++ * interrupt driven and handled over a GPIO loopback.
++ *
++ * Returns to userspace the array of deltas obtained during each capture.
++ * A total amount of INT_PERF_TEST_CAPTURES captures is performed.
++ *
++ */
++static int gpio_sc_interrupt_perf(unsigned long user_memloc)
++{
++ int ret = 0;
++ int irq = -1;
++ int gpio_input = SUT_GPIO_SC_1;
++ int gpio_output = SUT_GPIO_SC_0;
++ unsigned int i = 0;
++ cycles_t perf_t0 = 0;
++ cycles_t delta = 0;
++
++ /* Casting pointer to user-space location to write */
++ cycles_t __user *user_ptr = (cycles_t __user *)user_memloc;
++
++ /* Can we copy the captures array into user-space location? */
++ if (!access_ok(VERIFY_WRITE, user_ptr, sizeof(deltas))) {
++ pr_err("can't copy 0x%x bytes to user-space address 0x%p\n",
++ sizeof(deltas),user_ptr);
++ return -EFAULT;
++ }
++
++ /* Setup the GPIO */
++ if (!gpio_is_valid(gpio_input)) {
++ pr_err("gpio%d is invalid\n", gpio_input);
++ ret = -1;
++ goto fail;
++ }
++ if (!gpio_is_valid(gpio_output)) {
++ pr_err("gpio%d is invalid\n", gpio_output);
++ ret = -1;
++ goto fail;
++ }
++ ret = gpio_request_one(gpio_input, GPIOF_IN, "gpio_intperf_in");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio_input, ret);
++ goto fail;
++ }
++ ret = gpio_request_one(gpio_output, GPIOF_OUT_INIT_LOW, "gpio_intperf_out");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio_output, ret);
++ goto fail_release_input_gpio;
++ }
++
++ /* Setup IRQ handler for input GPIO */
++ irq = gpio_to_irq(gpio_input);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio_input);
++ goto fail_release_output_gpio;
++ }
++ if (0 != (ret = request_irq(irq, gpio_latency_handler,
++ IRQF_TRIGGER_RISING, "gpio_latency_handler", NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio_input);
++ goto fail_release_output_gpio;
++ }
++
++ /* Perform test */
++ for (i = 0; i < INT_PERF_TEST_CAPTURES; i ++) {
++ /* t0 */
++ perf_t0 = get_cycles();
++
++ /* Trigger interrupt */
++ gpio_set_value(gpio_output, 1);
++ mdelay(2);
++
++ /* Check for wrap-around and store delta */
++ if(perf_t0 < perf_t1) {
++ delta = perf_t1 - perf_t0;
++ } else {
++ delta = perf_t1 + (UINT64_MAX - perf_t0);
++ }
++ deltas[i] = delta;
++ }
++
++ /* Expose results to userspace */
++ ret = copy_to_user(user_ptr, &deltas, sizeof(deltas));
++
++ /* Release resources */
++
++ free_irq(irq, NULL);
++
++fail_release_output_gpio:
++ gpio_free(gpio_output);
++fail_release_input_gpio:
++ gpio_free(gpio_input);
++fail:
++ if (0 != ret) {
++ pr_err("%s() failed\n", __func__);
++ }
++
++ return ret;
++}
++
++/**
++ * gpio_sc_pm_test_int
++ *
++ * Request rising edge-triggered IRQ for SUT_GPIO_SC_0
++ */
++static int gpio_sc_pm_test_int(void)
++{
++ int ret = 0;
++ int irq = -1;
++ int gpio_input = SUT_GPIO_SC_0;
++
++ /* Setup the GPIO */
++ if (!gpio_is_valid(gpio_input)) {
++ pr_err("gpio%d is invalid\n", gpio_input);
++ ret = -1;
++ goto fail;
++ }
++ ret = gpio_request_one(gpio_input, GPIOF_IN, "gpio_pm_test_in");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio_input, ret);
++ goto fail;
++ }
++
++ /* Setup IRQ handler for input GPIO */
++ irq = gpio_to_irq(gpio_input);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio_input);
++ goto fail_release_input_gpio;
++ }
++ if (0 != (ret = request_irq(irq, gpio_pm_test_handler,
++ IRQF_TRIGGER_RISING, GPIO_PM_TEST_IRQ_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio_input);
++ goto fail_release_input_gpio;
++ }
++
++ return 0;
++
++fail_release_input_gpio:
++ gpio_free(gpio_input);
++fail:
++ return ret;
++}
++
++/**
++ * gpio_sc_pm_test_int
++ *
++ * Release resources reserved by gpio_sc_edge_int()
++ */
++static int gpio_sc_pm_test_int_teardown(void)
++{
++ int irq = -1;
++
++ irq = gpio_to_irq(SUT_GPIO_SC_0);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_0);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ gpio_free(SUT_GPIO_SC_0);
++
++ return 0;
++}
++
++/**
++ * gpio_sc_edge_int
++ *
++ * Request IRQ for SUT_GPIO_SC_6 and SUT_GPIO_SC_7, respectively positive-edge
++ * and negative edge-triggered.
++ * Mask the IRQs if requested.
++ */
++static int gpio_sc_edge_int(int masking)
++{
++ int ret = 0;
++ int irq_pos = -1, irq_neg = -1;
++
++ if (!gpio_is_valid(SUT_GPIO_SC_6)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_6);
++ ret = -1;
++ goto fail;
++ }
++ if (!gpio_is_valid(SUT_GPIO_SC_7)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_7);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(SUT_GPIO_SC_6, GPIOF_IN, "gpio_pos_edge");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_6, ret);
++ goto fail;
++ }
++ ret = gpio_request_one(SUT_GPIO_SC_7, GPIOF_IN, "gpio_neg_edge");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_7, ret);
++ goto fail_release_first_gpio;
++ }
++
++ irq_pos = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq_pos < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++ irq_neg = gpio_to_irq(SUT_GPIO_SC_7);
++ if (irq_neg < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_7);
++ goto fail_release_second_gpio;
++ }
++
++ if (0 != (ret = request_irq(irq_pos, gpio_pos_edge_handler,
++ IRQF_TRIGGER_RISING, GPIO_INT_EDGE_POS_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++ if (0 != (ret = request_irq(irq_neg, gpio_neg_edge_handler,
++ IRQF_TRIGGER_FALLING, GPIO_INT_EDGE_NEG_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_7);
++ goto fail_release_first_gpio_irq;
++ }
++
++ pr_info("Registered gpio%d and gpio%d IRQs\n", SUT_GPIO_SC_6,
++ SUT_GPIO_SC_7);
++
++ if (masking) {
++ disable_irq(gpio_to_irq(SUT_GPIO_SC_6));
++ disable_irq(gpio_to_irq(SUT_GPIO_SC_7));
++ pr_info("Masked gpio%d and gpio%d IRQs\n", SUT_GPIO_SC_6,
++ SUT_GPIO_SC_7);
++ }
++
++ return 0;
++
++fail_release_first_gpio_irq:
++ free_irq(irq_pos, NULL);
++fail_release_second_gpio:
++ gpio_free(SUT_GPIO_SC_7);
++fail_release_first_gpio:
++ gpio_free(SUT_GPIO_SC_6);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_edge_int_teardown
++ *
++ * Release resources reserved by gpio_sc_edge_int()
++ */
++static int gpio_sc_edge_int_teardown(void)
++{
++ int irq_pos = -1, irq_neg = -1;
++
++ irq_neg = gpio_to_irq(SUT_GPIO_SC_7);
++ if (irq_neg < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_7);
++ } else {
++ free_irq(irq_neg, NULL);
++ }
++ irq_pos = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq_pos < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ } else {
++ free_irq(irq_pos, NULL);
++ }
++
++ gpio_free(SUT_GPIO_SC_7);
++ gpio_free(SUT_GPIO_SC_6);
++
++ return 0;
++}
++
++/**
++ * gpio_sc_basic_int
++ *
++ * Register rising-edge interrupt handler on SUT_GPIO_SC_1
++ */
++static int gpio_sc_basic_int(void)
++{
++ int ret = 0;
++ int irq = -1;
++ unsigned int gpio = SUT_GPIO_SC_1;
++
++ if (!gpio_is_valid(gpio)) {
++ pr_err("gpio%d is invalid\n", gpio);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(gpio, GPIOF_IN, "gpio_pos_edge_basic");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio, ret);
++ goto fail;
++ }
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ if (0 != (ret = request_irq(irq, gpio_basic_handler,
++ IRQF_TRIGGER_RISING, GPIO_INT_BASIC_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ pr_info("Registered gpio%d IRQ\n", gpio);
++
++ return 0;
++
++fail_release_gpio:
++ gpio_free(gpio);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_basic_int_teardown
++ *
++ * Release resources reserved by gpio_sc_basic_int()
++ */
++static int gpio_sc_basic_int_teardown(void)
++{
++ int irq = -1;
++ unsigned int gpio = SUT_GPIO_SC_1;
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ gpio_free(gpio);
++
++ return 0;
++}
++
++/**
++ * gpio_spidev_register
++ *
++ * Register a bitbanged SPI platform device and export a `spidev' to userspace.
++ * For North Cluster and South Cluster.
++ */
++static int gpio_spidev_register(int north_cluster)
++{
++ /* Not needed anymore */
++ return 0;
++}
++
++/**
++ * gpio_spidev_unregister
++ *
++ * Release a bitbanged SPI platform device and its `spidev' interface.
++ * For North Cluster and South Cluster.
++ */
++static int gpio_spidev_unregister(int north_cluster)
++{
++ /* Not needed anymore */
++ return 0;
++}
++
++/**
++ * gip_system_power_transition
++ *
++ * @param state: 0 if transition to S3, !0 if transition to S0
++ * @return 0 success < 0 failure
++ *
++ * Exercise system-wide suspend/resume power management transitions.
++ *
++ */
++static int gip_system_power_transition(int state)
++{
++ struct pci_dev *gip = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0934, NULL);
++ if (NULL == gip) {
++ pr_err("can't find GIP PCI device\n");
++ return -ENOENT;
++ }
++
++ if (0 == state) {
++ gip->driver->driver.pm->suspend(&gip->dev);
++ } else {
++ gip->driver->driver.pm->resume(&gip->dev);
++ }
++
++ /* Decrement reference count of PCI device */
++ if (NULL != pci_get_device(PCI_VENDOR_ID_INTEL, 0x0934, gip)) {
++ pr_warn("found duplicate of GIP PCI device?!\n");
++ }
++
++ return 0;
++}
++
++/**
++ * gpio_nmi_enable
++ *
++ * @param enable: 0 to disable, !0 to enable
++ * @return 0 success < 0 failure
++ *
++ * Hack the legacy GPIO hardware to enable rising-edge triggered NMI on Core
++ * Well gpio0.
++ *
++ */
++static int gpio_nmi_enable(int enable)
++{
++ unsigned int base_u32 = 0x0;
++ unsigned short base = 0x0;
++ struct pci_dev *ilb = pci_get_device(PCI_VENDOR_ID_INTEL,
++ PCI_DEVICE_ID_INTEL_QUARK_ILB,
++ NULL);
++ /* Assume interrupts are disabled by default by BIOS */
++ unsigned char gpio = enable ? 0x01 : 0x00;
++
++ if (NULL == ilb) {
++ pr_err("can't find iLB device\n");
++ return -ENOENT;
++ }
++
++ /* The GPIO base address is @ offset 0x44. Sussed out from driver */
++ pci_read_config_dword(ilb, 0x44, &base_u32);
++ if (0x0 == base_u32) {
++ pr_err("can't read iLB GPIO baseaddr\n");
++ return -ENOENT;
++ }
++ base = (unsigned short)base_u32;
++
++ /*
++ * Prepare for rising edge NMI triggering. This assumes the pin
++ * is already set as input.
++ */
++#define CGTPE 0x0C /* Core Well trigger positive edge */
++#define CGTS 0x1C /* Core Well trigges status - W1C */
++#define CGNMIEN 0x40 /* Core Well NMI enable */
++ outb(0x01, base + CGTS);
++ outb(gpio, base + CGTPE);
++ outb(gpio, base + CGNMIEN);
++#undef CGTPE
++#undef CGTS
++#undef CGNMIEN
++
++ return 0;
++}
++
++/**
++ * gpio_sc_debounce
++ *
++ * Enable GPIO debounce functionality for SC_GPIO_1 (edge and level triggered)
++ *
++ */
++static int gpio_sc_debounce(int level)
++{
++ int ret = 0;
++ int irq = -1;
++ int gpio = SUT_GPIO_SC_0;
++
++ if (!gpio_is_valid(gpio)) {
++ pr_err("gpio%d is invalid\n", gpio);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(gpio, GPIOF_IN,
++ level ? "gpio_level_mask" : "gpio_edge_mask");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio, ret);
++ goto fail;
++ }
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ /*
++ * Register IRQ. gpio_pos_edge_handler will do for both level and edge
++ * interrupts, as it's nooping.
++ */
++ if (0 != (ret = request_irq(irq, gpio_pos_edge_handler,
++ level ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_RISING,
++ level ? GPIO_INT_LEVEL_HIGH_LABEL : GPIO_INT_EDGE_POS_LABEL,
++ NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ /* Set debounce */
++ if (0 != (ret = gpio_set_debounce(gpio, 1))) {
++ pr_err("can't set debounce for gpio%d\n", gpio);
++ goto fail_free_irq;
++ }
++
++ return 0;
++
++fail_free_irq:
++ free_irq(irq, NULL);
++fail_release_gpio:
++ gpio_free(gpio);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_debounce_teardown
++ *
++ * Undo gpio_sc_debounce
++ *
++ */
++static int gpio_sc_debounce_teardown(int level)
++{
++ int irq = -1;
++ unsigned int gpio = SUT_GPIO_SC_0;
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ gpio_free(gpio);
++
++ return 0;
++}
++
++/*
++ * File ops
++ */
++static long gip_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -EINVAL;
++
++ switch (cmd) {
++ case IOCTL_QRK_GPIO_11:
++ /* Edge-triggered interrupts */
++ ret = gpio_sc_edge_int(0);
++ break;
++ case IOCTL_QRK_GPIO_11_CLEANUP:
++ /* Edge-triggered interrupts cleanup */
++ ret = gpio_sc_edge_int_teardown();
++ break;
++ case IOCTL_QRK_GPIO_12:
++ /* Edge-triggered interrupts (masking) */
++ ret = gpio_sc_edge_int(1);
++ break;
++ case IOCTL_QRK_GPIO_12_CLEANUP:
++ /* Edge-triggered interrupts (masking) cleanup */
++ ret = gpio_sc_edge_int_teardown();
++ break;
++ case IOCTL_QRK_GPIO_13:
++ /* GPIO debounce (edge) */
++ ret = gpio_sc_debounce(0);
++ break;
++ case IOCTL_QRK_GPIO_13_CLEANUP:
++ /* GPIO debounce cleanup (edge) */
++ ret = gpio_sc_debounce_teardown(0);
++ break;
++ case IOCTL_QRK_GPIO_14:
++ /* High-level triggered interrupts */
++ ret = gpio_sc_level_int(1, 0);
++ break;
++ case IOCTL_QRK_GPIO_14_CLEANUP:
++ /* High-level triggered interrupts cleanup */
++ ret = gpio_sc_level_int_teardown();
++ break;
++ case IOCTL_QRK_GPIO_15:
++ /* Low-level triggered interrupts */
++ ret = gpio_sc_level_int(0, 0);
++ break;
++ case IOCTL_QRK_GPIO_15_CLEANUP:
++ /*Low-level triggered interrupts cleanup */
++ ret = gpio_sc_level_int_teardown();
++ break;
++ case IOCTL_QRK_GPIO_16:
++ /* Level triggered interrupts (masking) */
++ ret = gpio_sc_level_int(1, 1);
++ break;
++ case IOCTL_QRK_GPIO_16_CLEANUP:
++ /* Level triggered interrupts (masking) cleanup */
++ ret = gpio_sc_level_int_teardown();
++ break;
++ case IOCTL_QRK_GPIO_17:
++ /* GPIO debounce (level) */
++ ret = gpio_sc_debounce(1);
++ break;
++ case IOCTL_QRK_GPIO_17_CLEANUP:
++ /* GPIO debounce cleanup (level) */
++ ret = gpio_sc_debounce_teardown(1);
++ break;
++ case IOCTL_QRK_GPIO_19:
++ /* Register IRQ for SC_GPIO0 (PM transitions test) */
++ ret = gpio_sc_pm_test_int();
++ break;
++ case IOCTL_QRK_GPIO_19_CLEANUP:
++ /* Free IRQ for SC_GPIO0 (PM transitions test) */
++ ret = gpio_sc_pm_test_int_teardown();
++ break;
++ case IOCTL_QRK_GPIO_20:
++ /* NC bitbanged SPI */
++ ret = gpio_spidev_register(1);
++ break;
++ case IOCTL_QRK_GPIO_20_CLEANUP:
++ /* NC bitbanged SPI cleanup */
++ ret = gpio_spidev_unregister(1);
++ break;
++ case IOCTL_QRK_GPIO_21:
++ /* SC bitbanged SPI */
++ ret = gpio_spidev_register(0);
++ break;
++ case IOCTL_QRK_GPIO_21_CLEANUP:
++ /* SC bitbanged SPI cleanup */
++ ret = gpio_spidev_unregister(0);
++ break;
++ case IOCTL_QRK_GPIO_24:
++ /*
++ * SC GPIO interrupt performance test.
++ * Note it's shared between QRK_GPIO_24 and QRK_GPIO_25
++ * plus it doesn't need any cleanup call.
++ */
++ ret = gpio_sc_interrupt_perf(arg);
++ break;
++ case IOCTL_QRK_GPIO_26:
++ /* Interrupt for basic loopback test */
++ ret = gpio_sc_basic_int();
++ break;
++ case IOCTL_QRK_GPIO_26_CLEANUP:
++ /* Interrupt for basic loopback test cleanup */
++ ret = gpio_sc_basic_int_teardown();
++ break;
++ case IOCTL_QRK_GIP_SYSTEM_SUSPEND:
++ ret = gip_system_power_transition(0);
++ break;
++ case IOCTL_QRK_GIP_SYSTEM_RESUME:
++ ret = gip_system_power_transition(1);
++ break;
++ case IOCTL_QRK_GPIO_NMI_ENABLE:
++ ret = gpio_nmi_enable(1);
++ break;
++ case IOCTL_QRK_GPIO_NMI_DISABLE:
++ ret = gpio_nmi_enable(0);
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int gip_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&gip_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&gip_test_dev.open_lock)) {
++ mutex_unlock(&gip_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (gip_test_dev.opened) {
++ mutex_unlock(&gip_test_dev.open_lock);
++ mutex_unlock(&gip_test_mutex);
++ return -EINVAL;
++ }
++
++ gip_test_dev.opened++;
++ mutex_unlock(&gip_test_dev.open_lock);
++ mutex_unlock(&gip_test_mutex);
++ return 0;
++}
++
++static int gip_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&gip_test_dev.open_lock);
++ gip_test_dev.opened = 0;
++ mutex_unlock(&gip_test_dev.open_lock);
++
++ return 0;
++}
++
++static const struct file_operations gip_test_file_ops = {
++ .open = gip_test_open,
++ .release = gip_test_release,
++ .unlocked_ioctl = gip_test_ioctl,
++ .llseek = no_llseek,
++};
++
++/**
++ * intel_qrk_gip_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ */
++static int intel_qrk_gip_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ mutex_init(&gip_test_dev.open_lock);
++ cdev_init(&gip_test_dev.cdev, &gip_test_file_ops);
++ gip_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&gip_test_dev.cdev, MKDEV(gip_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(gip_test_class, NULL,
++ MKDEV(gip_test_major, minor), NULL,
++ "giptest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ return -EINVAL;
++ }
++
++ return 0;
++
++}
++
++static int intel_qrk_gip_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(gip_test_dev.cdev.dev);
++
++ device_destroy(gip_test_class, MKDEV(gip_test_major, minor));
++ cdev_del(&gip_test_dev.cdev);
++
++ class_destroy(gip_test_class);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_qrk_gip_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_qrk_gip_test_remove,
++};
++
++/**
++ * intel_qrk_gip_test_init
++ *
++ * Load module.
++ */
++static int __init intel_qrk_gip_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ gip_test_class = class_create(THIS_MODULE,"qrk_gip_test");
++ if (IS_ERR(gip_test_class)) {
++ retval = PTR_ERR(gip_test_class);
++ printk(KERN_ERR "gip_test: can't register gip_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "gip_test");
++ if (retval) {
++ printk(KERN_ERR "earam_test: can't register character device\n");
++ goto err_class;
++ }
++ gip_test_major = MAJOR(dev);
++
++ memset(&gip_test_dev, 0x00, sizeof(gip_test_dev));
++ gip_test_dev.pldev = platform_create_bundle(
++ &intel_qrk_gip_test_driver, intel_qrk_gip_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(gip_test_dev.pldev)){
++ printk(KERN_ERR "platform_create_bundle fail!\n");
++ retval = PTR_ERR(gip_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(gip_test_class);
++err:
++ return retval;
++}
++
++static void __exit intel_qrk_gip_test_exit(void)
++{
++ platform_device_unregister(gip_test_dev.pldev);
++ platform_driver_unregister(&intel_qrk_gip_test_driver);
++}
++
++module_init(intel_qrk_gip_test_init);
++module_exit(intel_qrk_gip_test_exit);
++
++MODULE_AUTHOR("Josef Ahmad <josef.ahmad@intel.com>");
++MODULE_DESCRIPTION("Quark GIP test module");
++MODULE_LICENSE("Dual BSD/GPL");
++
+diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
+index 5624fcb..4afc687 100644
+--- a/drivers/mfd/lpc_sch.c
++++ b/drivers/mfd/lpc_sch.c
+@@ -41,21 +41,41 @@
+ #define WDTBASE 0x84
+ #define WDT_IO_SIZE 64
+
++/* BIOS control reg */
++#define LPC_BIOS_CNTL 0xD8
++#define LPC_BIOS_CNTL_WE 0x01
++
++/* Root complex base address derived registers */
++#define RCBA_BASE 0xF0
++
+ static struct resource smbus_sch_resource = {
+ .flags = IORESOURCE_IO,
+ };
+
+-
+ static struct resource gpio_sch_resource = {
+ .flags = IORESOURCE_IO,
+ };
+
++static struct resource spi_res = {
++ .flags = IORESOURCE_MEM,
++ .start = 0,
++ .end = 0,
++};
++
++static struct platform_device lpc_sch_spi = {
++ .name = "spi-lpc-sch",
++ .id = -1,
++ .resource = &spi_res,
++};
++
+ static struct mfd_cell lpc_sch_cells[] = {
++#ifndef CONFIG_INTEL_QUARK_X1000_SOC
+ {
+ .name = "isch_smbus",
+ .num_resources = 1,
+ .resources = &smbus_sch_resource,
+ },
++#endif
+ {
+ .name = "sch_gpio",
+ .num_resources = 1,
+@@ -79,6 +99,7 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QUARK_ILB) },
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
+@@ -88,22 +109,26 @@ static int lpc_sch_probe(struct pci_dev *dev,
+ {
+ unsigned int base_addr_cfg;
+ unsigned short base_addr;
++ u32 rcba_base, bios_cntl;
+ int i;
+ int ret;
+
+- pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
+- if (!(base_addr_cfg & (1 << 31))) {
+- dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
+- return -ENODEV;
+- }
+- base_addr = (unsigned short)base_addr_cfg;
+- if (base_addr == 0) {
+- dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
+- return -ENODEV;
+- }
++ /* Quark does not support iLB SMBUS */
++ if (id->device != PCI_DEVICE_ID_INTEL_QUARK_ILB) {
++ pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
++ if (!(base_addr_cfg & (1 << 31))) {
++ dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
++ return -ENODEV;
++ }
++ base_addr = (unsigned short)base_addr_cfg;
++ if (base_addr == 0) {
++ dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
++ return -ENODEV;
++ }
+
+- smbus_sch_resource.start = base_addr;
+- smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
++ smbus_sch_resource.start = base_addr;
++ smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
++ }
+
+ pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+ if (!(base_addr_cfg & (1 << 31))) {
+@@ -132,6 +157,31 @@ static int lpc_sch_probe(struct pci_dev *dev,
+ if (ret)
+ goto out_dev;
+
++ /* Add RCBA SPI device */
++ if (id->device == PCI_DEVICE_ID_INTEL_QUARK_ILB) {
++ pci_read_config_dword(dev, LPC_BIOS_CNTL, &bios_cntl);
++ pr_info("%s BIOS_CNTL 0x%08x\n", __func__, bios_cntl);
++
++ /* Enable flash write */
++ bios_cntl |= LPC_BIOS_CNTL_WE;
++ pci_write_config_dword(dev, LPC_BIOS_CNTL, bios_cntl);
++
++ /* Verify */
++ pci_read_config_dword(dev, LPC_BIOS_CNTL, &bios_cntl);
++ pr_info("%s new BIOS_CNTL 0x%08x\n", __func__, bios_cntl);
++ }
++
++ pci_read_config_dword(dev, RCBA_BASE, &rcba_base);
++ rcba_base &= 0xFFFFC000;
++ spi_res.start = rcba_base + 0x3020;
++ spi_res.end = rcba_base + 0x3088;
++ pr_info("%s RCBA @ 0x%08x\n", __func__, rcba_base);
++ ret = platform_device_register(&lpc_sch_spi);
++ if (ret < 0){
++ pr_err("unable to register %s plat dev\n", lpc_sch_spi.name);
++ goto out_dev;
++ }
++
+ 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
+new file mode 100644
+index 0000000..a32c6f0
+--- /dev/null
++++ b/include/linux/mfd/cy8c9540a.h
+@@ -0,0 +1,38 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++#ifndef LINUX_CY8C9540A_PDATA_H
++#define LINUX_CY8C9540A_PDATA_H
++
++#include <linux/types.h>
++
++#define CY8C9540A_POR_SETTINGS_LEN 147
++#define CY8C9540A_NPWM 8
++#define CY8C9540A_PWM_UNUSED -1
++
++struct cy8c9540a_pdata {
++ u8 por_default[CY8C9540A_POR_SETTINGS_LEN];
++ int pwm2gpio_mapping[CY8C9540A_NPWM];
++ int gpio_base;
++ int pwm_base;
++ int irq_base;
++};
++
++#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
+--- /dev/null
++++ b/include/linux/mfd/intel_qrk_gip_pdata.h
+@@ -0,0 +1,32 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++#ifndef LINUX_INTEL_QRK_GIP_DATA_H
++#define LINUX_INTEL_QRK_GIP_DATA_H
++
++struct pci_dev;
++
++struct intel_qrk_gip_pdata {
++ int i2c_std_mode;
++};
++
++extern struct intel_qrk_gip_pdata *(*intel_qrk_gip_get_pdata)(void);
++
++#endif
+--
+1.7.4.1
+
diff --git a/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch b/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch
new file mode 100644
index 0000000..a730cca
--- /dev/null
+++ b/recipes-kernel/linux/files/0017-Quark-I2C-quark.patch
@@ -0,0 +1,417 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Josef Ahmad <josef.ahmad@linux.intel.com>
+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 +++--
+ 4 files changed, 123 insertions(+), 25 deletions(-)
+
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index bdca511..010e4fd 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -22,7 +22,7 @@ config I2C_ALI1535
+
+ config I2C_ALI1563
+ tristate "ALI 1563"
+- depends on PCI && EXPERIMENTAL
++ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SMB
+ Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
+@@ -56,7 +56,7 @@ config I2C_AMD756
+
+ config I2C_AMD756_S4882
+ tristate "SMBus multiplexing on the Tyan S4882"
+- depends on I2C_AMD756 && X86 && EXPERIMENTAL
++ depends on I2C_AMD756 && X86
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
+@@ -164,7 +164,7 @@ config I2C_NFORCE2
+
+ config I2C_NFORCE2_S4985
+ tristate "SMBus multiplexing on the Tyan S4985"
+- depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
++ depends on I2C_NFORCE2 && X86
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
+@@ -215,7 +215,7 @@ config I2C_SIS96X
+
+ config I2C_VIA
+ tristate "VIA VT82C586B"
+- depends on PCI && EXPERIMENTAL
++ depends on PCI
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be included for the VIA
+@@ -267,7 +267,7 @@ comment "Mac SMBus host controller drivers"
+
+ config I2C_HYDRA
+ tristate "CHRP Apple Hydra Mac I/O I2C interface"
+- depends on PCI && PPC_CHRP && EXPERIMENTAL
++ depends on PCI && PPC_CHRP
+ select I2C_ALGOBIT
+ help
+ This supports the use of the I2C interface in the Apple Hydra Mac
+@@ -293,7 +293,7 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
+ config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+- depends on ARCH_AT91 && EXPERIMENTAL
++ depends on ARCH_AT91
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+@@ -386,7 +386,7 @@ config I2C_DESIGNWARE_PLATFORM
+
+ config I2C_DESIGNWARE_PCI
+ tristate "Synopsys DesignWare PCI"
+- depends on PCI
++ depends on PCI && !INTEL_QUARK_X1000_SOC
+ select I2C_DESIGNWARE_CORE
+ help
+ If you say yes to this option, support will be included for the
+@@ -519,7 +519,6 @@ config I2C_NUC900
+
+ config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+- depends on EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+@@ -712,7 +711,7 @@ config I2C_OCTEON
+
+ config I2C_XILINX
+ tristate "Xilinx I2C Controller"
+- depends on EXPERIMENTAL && HAS_IOMEM
++ depends on HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ Xilinx I2C controller.
+@@ -803,7 +802,7 @@ config I2C_PARPORT_LIGHT
+
+ config I2C_TAOS_EVM
+ tristate "TAOS evaluation module"
+- depends on EXPERIMENTAL
++ depends on TTY
+ select SERIO
+ select SERIO_SERPORT
+ default n
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index f5258c2..2a2d1c9 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -164,6 +164,29 @@ static char *abort_sources[] = {
+ "lost arbitration",
+ };
+
++/*
++ * Bitmask for struct i2c_dw_data_cmd's `cmd' field.
++ * - DW_IC_CMD_READ: read/~write operation
++ * - DW_IC_CMD_STOP: stop condition generation (only for devices requiring
++ * explicit transaction termination)
++ * - DW_IC_CMD_RESTART: (re)start condition generation (only for devices
++ * requiring explicit transaction termination)
++ */
++#define DW_IC_CMD_READ 0x01
++#define DW_IC_CMD_STOP 0x02
++#define DW_IC_CMD_RESTART 0x04
++
++/*
++ * Define the IC_DATA_CMD format.
++ */
++static union i2c_dw_data_cmd {
++ struct fields {
++ u8 data;
++ u8 cmd;
++ } fields;
++ u16 value;
++} data_cmd;
++
+ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+ {
+ u32 value;
+@@ -344,6 +367,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ struct i2c_msg *msgs = dev->msgs;
+ u32 ic_con;
+
++ /* Disable interrupts */
++ i2c_dw_disable_int(dev);
++
+ /* Disable the adapter */
+ dw_writel(dev, 0, DW_IC_ENABLE);
+
+@@ -380,6 +406,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ u32 addr = msgs[dev->msg_write_idx].addr;
+ u32 buf_len = dev->tx_buf_len;
+ u8 *buf = dev->tx_buf;
++ int segment_start = 0;
+
+ intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+@@ -403,21 +430,65 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ break;
+ }
+
++ segment_start = 0;
+ if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+ /* new i2c_msg */
+ buf = msgs[dev->msg_write_idx].buf;
+ buf_len = msgs[dev->msg_write_idx].len;
++ segment_start = 1;
+ }
+
+ tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
+ rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+
++ /*
++ * The maximum number of read requests that can be put into TX
++ * FIFO depends on the number read operations already pending
++ * in RX FIFO + the number of outstanding read operations still
++ * queued in the TX FIFO.
++ * This prevents RX FIFO overrun.
++ */
++ rx_limit -= dev->rx_outstanding;
++
+ while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
++ data_cmd.fields.data = 0x00;
++ data_cmd.fields.cmd = 0x00;
++
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+- dw_writel(dev, 0x100, DW_IC_DATA_CMD);
++ /* Master-receiver */
++ data_cmd.fields.cmd = DW_IC_CMD_READ;
+ rx_limit--;
+- } else
+- dw_writel(dev, *buf++, DW_IC_DATA_CMD);
++ dev->rx_outstanding++;
++ } else {
++ /* Master-transmitter */
++ data_cmd.fields.data = *buf;
++ buf++;
++ }
++
++ if (1 == dev->explicit_stop
++ && 1 == segment_start) {
++ /*
++ * First byte of a transaction segment for a
++ * device requiring explicit transaction
++ * termination: generate (re)start symbol.
++ */
++ segment_start = 0;
++ data_cmd.fields.cmd |= DW_IC_CMD_RESTART;
++ }
++
++ if (1 == dev->explicit_stop
++ && dev->msg_write_idx == dev->msgs_num - 1
++ && 1 == buf_len) {
++ /*
++ * Last byte of last transction segment for a
++ * device requiring explicit transaction
++ * termination: generate stop symbol.
++ */
++ data_cmd.fields.cmd |= DW_IC_CMD_STOP;
++ }
++
++ dw_writel(dev, data_cmd.value, DW_IC_DATA_CMD);
++
+ tx_limit--; buf_len--;
+ }
+
+@@ -468,8 +539,10 @@ i2c_dw_read(struct dw_i2c_dev *dev)
+
+ rx_valid = dw_readl(dev, DW_IC_RXFLR);
+
+- for (; len > 0 && rx_valid > 0; len--, rx_valid--)
++ for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
+ *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
++ dev->rx_outstanding--;
++ }
+
+ if (len > 0) {
+ dev->status |= STATUS_READ_IN_PROGRESS;
+@@ -527,6 +600,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
++ dev->rx_outstanding = 0;
+
+ ret = i2c_dw_wait_bus_not_busy(dev);
+ if (ret < 0)
+@@ -625,8 +699,6 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+- if (stat & DW_IC_INTR_STOP_DET)
+- dw_readl(dev, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+@@ -677,8 +749,21 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+ * the current transmit status.
+ */
+
++ /*
++ * Process stop condition after the last transaction segment is
++ * transmitted (and received if appropriate).
++ */
++ if (dev->msgs_num == dev->msg_write_idx
++ && (DW_IC_INTR_STOP_DET & dw_readl(dev, DW_IC_INTR_STAT))
++ && 0 == dw_readl(dev, DW_IC_TXFLR)
++ && 0 == dw_readl(dev, DW_IC_RXFLR)
++ && 0 == dev->rx_outstanding) {
++ dw_readl(dev, DW_IC_CLR_STOP_DET);
++ complete(&dev->cmd_complete);
++ }
++
+ tx_aborted:
+- if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
++ if ((stat & (DW_IC_INTR_TX_ABRT)) || dev->msg_err)
+ complete(&dev->cmd_complete);
+
+ return IRQ_HANDLED;
+diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
+index 9c1840e..691aff8 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -34,6 +34,14 @@
+ #define DW_IC_CON_RESTART_EN 0x20
+ #define DW_IC_CON_SLAVE_DISABLE 0x40
+
++struct dw_pci_controller {
++ u32 bus_num;
++ u32 bus_cfg;
++ u32 tx_fifo_depth;
++ u32 rx_fifo_depth;
++ u32 clk_khz;
++ u8 explicit_stop;
++};
+
+ /**
+ * struct dw_i2c_dev - private i2c-designware data
+@@ -60,6 +68,8 @@
+ * @adapter: i2c subsystem adapter node
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
++ * @rx_outstanding: current outstanding master-receiver bytes in TX FIFO
++ * @explicit_stop: set to 1 if hardware requires explicit stop bit transmission
+ */
+ struct dw_i2c_dev {
+ struct device *dev;
+@@ -88,6 +98,8 @@ struct dw_i2c_dev {
+ u32 master_cfg;
+ unsigned int tx_fifo_depth;
+ unsigned int rx_fifo_depth;
++ int rx_outstanding;
++ u8 explicit_stop;
+ };
+
+ #define ACCESS_SWAP 0x00000001
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 6add851..62ad7dc 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -56,14 +56,6 @@ enum dw_pci_ctl_id_t {
+ medfield_5,
+ };
+
+-struct dw_pci_controller {
+- u32 bus_num;
+- u32 bus_cfg;
+- u32 tx_fifo_depth;
+- u32 rx_fifo_depth;
+- u32 clk_khz;
+-};
+-
+ #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
+ DW_IC_CON_SLAVE_DISABLE | \
+ DW_IC_CON_RESTART_EN)
+@@ -75,6 +67,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [moorestown_1] = {
+ .bus_num = 1,
+@@ -82,6 +75,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [moorestown_2] = {
+ .bus_num = 2,
+@@ -89,6 +83,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_0] = {
+ .bus_num = 0,
+@@ -96,6 +91,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_1] = {
+ .bus_num = 1,
+@@ -103,6 +99,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_2] = {
+ .bus_num = 2,
+@@ -110,6 +107,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_3] = {
+ .bus_num = 3,
+@@ -117,6 +115,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_4] = {
+ .bus_num = 4,
+@@ -124,6 +123,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_5] = {
+ .bus_num = 5,
+@@ -131,6 +131,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ };
+ static struct i2c_algorithm i2c_dw_algo = {
+@@ -282,6 +283,7 @@ const struct pci_device_id *id)
+
+ dev->tx_fifo_depth = controller->tx_fifo_depth;
+ dev->rx_fifo_depth = controller->rx_fifo_depth;
++ dev->explicit_stop = controller->explicit_stop;
+ 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
new file mode 100644
index 0000000..e59a7de
--- /dev/null
+++ b/recipes-kernel/linux/files/0018-Quark-sensors-quark.patch
@@ -0,0 +1,2155 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Dan O'Donovan <dan.odonovan@emutex.com>
+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(-)
+ 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
+ create mode 100644 drivers/iio/common/st_sensors/st_sensors_buffer.c
+ create mode 100644 drivers/iio/common/st_sensors/st_sensors_core.c
+ create mode 100644 drivers/iio/common/st_sensors/st_sensors_i2c.c
+ create mode 100644 drivers/iio/common/st_sensors/st_sensors_spi.c
+ create mode 100644 drivers/iio/common/st_sensors/st_sensors_trigger.c
+ create mode 100644 include/linux/iio/common/st_sensors.h
+ create mode 100644 include/linux/iio/common/st_sensors_i2c.h
+ create mode 100644 include/linux/iio/common/st_sensors_spi.h
+ create mode 100644 include/linux/platform_data/lis331dlh_intel_qrk.h
+
+diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
+index 05e996f..be6ded3 100644
+--- a/drivers/iio/accel/Kconfig
++++ b/drivers/iio/accel/Kconfig
+@@ -13,5 +13,13 @@ config HID_SENSOR_ACCEL_3D
+ help
+ Say yes here to build support for the HID SENSOR
+ accelerometers 3D.
++
++config IIO_LIS331DLH_INTEL_QRK
++ tristate "STMicroelectronics LIS331DLH accelerometer i2c driver for Intel Quark platform"
++ depends on INTEL_QUARK_X1000_SOC
++ depends on I2C && SYSFS
++ select IIO_ST_SENSORS_CORE
++ help
++ Selects the LIS331DLH accelerometer driver for the Intel Clanton Hill platform
+
+ endmenu
+diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
+index 5bc6855..81f8085 100644
+--- a/drivers/iio/accel/Makefile
++++ b/drivers/iio/accel/Makefile
+@@ -3,3 +3,5 @@
+ #
+
+ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
++
++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
+--- /dev/null
++++ b/drivers/iio/accel/lis331dlh_intel_qrk.c
+@@ -0,0 +1,735 @@
++/*
++ * 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.
++ *
++ * 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
++ *
++ * Derived from STMicroelectronics accelerometers driver by Denis Ciocca
++ *
++ * The Intel Clanton Hill platform hardware design includes an
++ * STMicroelectronics LIS331DLH accelerometer, intended to be used mainly for
++ * sensing orientation, movement and sudden impacts (e.g. vehicle collision)
++ *
++ * This driver plugs into the Linux Industrial-IO framework to provide a
++ * standardised user-space application interface for retreiving data and events
++ * from the accelerometer.
++ *
++ * The LIS331DLH is connected via I2C to the host CPU on the Clanton Hill
++ * platform and so this driver registers to the kernel as an I2C device driver
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/mutex.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/gpio.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/sysfs.h>
++#include <linux/iio/events.h>
++
++#include <linux/iio/common/st_sensors.h>
++#include <linux/iio/common/st_sensors_i2c.h>
++
++#include <linux/platform_data/lis331dlh_intel_qrk.h>
++
++/* DEFAULT VALUE FOR SENSORS */
++#define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28
++#define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a
++#define ST_ACCEL_DEFAULT_OUT_Z_L_ADDR 0x2c
++
++/* FULLSCALE */
++#define ST_ACCEL_FS_AVL_2G 2
++#define ST_ACCEL_FS_AVL_4G 4
++#define ST_ACCEL_FS_AVL_6G 6
++#define ST_ACCEL_FS_AVL_8G 8
++#define ST_ACCEL_FS_AVL_16G 16
++
++/* CUSTOM VALUES FOR SENSOR 2 */
++#define ST_ACCEL_2_WAI_EXP 0x32
++#define ST_ACCEL_2_ODR_ADDR 0x20
++#define ST_ACCEL_2_ODR_MASK 0x18
++#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00
++#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01
++#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02
++#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03
++#define ST_ACCEL_2_PW_ADDR 0x20
++#define ST_ACCEL_2_PW_MASK 0xe0
++#define ST_ACCEL_2_PW_DOWN 0x00
++#define ST_ACCEL_2_PW_NORMAL 0x20
++#define ST_ACCEL_2_CTRL_REG1_XEN 0x01
++#define ST_ACCEL_2_CTRL_REG1_YEN 0x02
++#define ST_ACCEL_2_CTRL_REG1_ZEN 0x04
++#define ST_ACCEL_2_FS_ADDR 0x23
++#define ST_ACCEL_2_FS_MASK 0x30
++#define ST_ACCEL_2_FS_AVL_2_VAL 0X00
++#define ST_ACCEL_2_FS_AVL_4_VAL 0X01
++#define ST_ACCEL_2_FS_AVL_8_VAL 0x03
++#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
++#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
++#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900)
++#define ST_ACCEL_2_BDU_ADDR 0x23
++#define ST_ACCEL_2_BDU_MASK 0x80
++#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
++#define ST_ACCEL_2_DRDY_IRQ_MASK 0x02
++#define ST_ACCEL_2_THRESH_IRQ_ADDR 0x30
++#define ST_ACCEL_2_THRESH_IRQ_MASK 0x7f
++#define ST_ACCEL_2_INT1_CFG_ADDR 0x30
++#define ST_ACCEL_2_INT1_SRC_ADDR 0x31
++#define ST_ACCEL_2_INT1_THRESH_ADDR 0x32
++#define ST_ACCEL_2_INT1_DURATION_ADDR 0x33
++#define ST_ACCEL_2_INT2_CFG_ADDR 0x34
++#define ST_ACCEL_2_INT2_SRC_ADDR 0x35
++#define ST_ACCEL_2_INT2_THRESH_ADDR 0x36
++#define ST_ACCEL_2_INT2_DURATION_ADDR 0x37
++#define ST_ACCEL_2_INT_IA_MASK 0x40
++#define ST_ACCEL_2_INT_LIR_MASK 0x05
++#define ST_ACCEL_2_INT_SRC_HIGH_MASK 0x20
++#define ST_ACCEL_2_INT_CFG_XLIE_EN 0x01
++#define ST_ACCEL_2_INT_CFG_XHIE_EN 0x02
++#define ST_ACCEL_2_INT_CFG_YLIE_EN 0x04
++#define ST_ACCEL_2_INT_CFG_YHIE_EN 0x08
++#define ST_ACCEL_2_INT_CFG_ZLIE_EN 0x10
++#define ST_ACCEL_2_INT_CFG_ZHIE_EN 0x20
++
++#define ST_ACCEL_2_MULTIREAD_BIT true
++#define ST_ACCEL_2_THRESH_VAL_MIN 0x00
++#define ST_ACCEL_2_THRESH_VAL_MAX 0x7f
++#define QRK_ACCEL_INT2_WAKEUP_THRESH_VAL 0x7f
++
++#define QRK_ACCEL_INT1_DISABLED 0
++#define QRK_ACCEL_INT1_ENABLED 1
++
++#define QRK_ACCEL_LSM_CHANNELS(device_type, index, mod, endian, bits, addr) \
++{ \
++ .type = device_type, \
++ .modified = 1, \
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
++ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
++ .scan_index = index, \
++ .channel = mod, \
++ .channel2 = mod, \
++ .address = addr, \
++ .scan_type = { \
++ .sign = 's', \
++ .realbits = bits, \
++ .shift = 16 - bits, \
++ .storagebits = 16, \
++ .endianness = endian, \
++ }, \
++ .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), \
++}
++
++static const u8 iio_modifier_map[] = {
++ IIO_NO_MOD,
++ IIO_MOD_X,
++ IIO_MOD_Y,
++ IIO_MOD_X_AND_Y,
++ IIO_MOD_Z,
++ IIO_MOD_X_AND_Z,
++ IIO_MOD_Y_AND_Z,
++ IIO_MOD_X_AND_Y_AND_Z,
++};
++
++/* Threshold event ISR bottom half. This function reads interrupt status
++ * registers for INT1 to reset any active interrupt conditions
++ * and pushes an IIO event if a threshold interrupt was active.
++ */
++static irqreturn_t lis331dlh_intel_qrk_threshold_event_handler(
++ int irq,
++ void *private)
++{
++ int err;
++ u8 data;
++ u8 mask;
++ int i;
++ u64 iio_modifier;
++
++ struct st_sensor_data *sdata = iio_priv(private);
++ s64 timestamp = iio_get_time_ns();
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_SRC_ADDR,
++ &data);
++
++ if (err < 0)
++ goto st_sensors_read_err;
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_CFG_ADDR,
++ &mask);
++
++ if (err < 0)
++ goto st_sensors_read_err;
++
++ if (data & ST_ACCEL_2_INT_IA_MASK) {
++ data &= mask;
++
++ iio_modifier = 0;
++ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
++ iio_modifier <<= 1;
++ iio_modifier += !!(data & ST_ACCEL_2_INT_SRC_HIGH_MASK);
++ data <<= 2;
++ }
++
++ iio_modifier = iio_modifier_map[iio_modifier];
++
++ iio_push_event(private,
++ IIO_MOD_EVENT_CODE(IIO_ACCEL,
++ 0,
++ iio_modifier,
++ IIO_EV_TYPE_THRESH,
++ IIO_EV_DIR_RISING),
++ timestamp);
++ }
++
++st_sensors_read_err:
++ return IRQ_HANDLED;
++}
++
++static inline int lis331dlh_intel_qrk_read_info_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *ch, int *val)
++{
++ int err;
++
++ mutex_lock(&indio_dev->mlock);
++ err = st_sensors_read_axis_data(indio_dev, ch->address, val);
++
++ if (unlikely(err < 0))
++ goto read_error;
++
++ *val = *val >> ch->scan_type.shift;
++ mutex_unlock(&indio_dev->mlock);
++
++ return err;
++
++read_error:
++ mutex_unlock(&indio_dev->mlock);
++ return err;
++}
++
++static int lis331dlh_intel_qrk_read_raw(
++ struct iio_dev *indio_dev,
++ struct iio_chan_spec const *ch,
++ int *val, int *val2, long mask)
++{
++ int err;
++ struct st_sensor_data *adata = iio_priv(indio_dev);
++
++ switch (mask) {
++ case IIO_CHAN_INFO_RAW:
++ err = lis331dlh_intel_qrk_read_info_raw(indio_dev, ch, val);
++ if (unlikely(err < 0))
++ goto read_error;
++
++ return IIO_VAL_INT;
++ case IIO_CHAN_INFO_SCALE:
++ *val = 0;
++ *val2 = adata->current_fullscale->gain;
++ return IIO_VAL_INT_PLUS_MICRO;
++ default:
++ return -EINVAL;
++ }
++
++read_error:
++ return err;
++}
++
++static int lis331dlh_intel_qrk_write_raw(
++ struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int val, int val2, long mask)
++{
++ int err;
++
++ switch (mask) {
++ case IIO_CHAN_INFO_SCALE:
++ err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return err;
++}
++
++static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
++static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
++static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
++
++static struct attribute *lis331dlh_intel_qrk_attributes[] = {
++ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
++ &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
++ &iio_dev_attr_sampling_frequency.dev_attr.attr,
++ NULL,
++};
++
++static const struct attribute_group lis331dlh_intel_qrk_attribute_group = {
++ .attrs = lis331dlh_intel_qrk_attributes,
++};
++
++static int lis331dlh_intel_qrk_read_event_value(
++ struct iio_dev *indio_dev,
++ u64 event_code,
++ int *val)
++{
++ int err;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_THRESH_ADDR, &data);
++
++ *val = (int) data;
++ return err;
++}
++
++static int lis331dlh_intel_qrk_write_event_value(
++ struct iio_dev *indio_dev,
++ u64 event_code,
++ int val)
++{
++ int err;
++ struct st_sensor_data *sdata;
++
++ /* range check */
++ if (unlikely((val < ST_ACCEL_2_THRESH_VAL_MIN) ||
++ (val > ST_ACCEL_2_THRESH_VAL_MAX)))
++ return -EINVAL;
++
++ sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_THRESH_ADDR, val);
++
++ return err;
++}
++
++/* Configure the INT1 pin to fire an interrupt on a high threshold event.
++ */
++static int lis331dlh_intel_qrk_configure_threshold_interrupt(
++ struct iio_dev *indio_dev, u8 state)
++{
++ int err = 0;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ if (sdata->sensor->drdy_irq.ig1.en_mask == state)
++ return 0;
++
++ if (state == QRK_ACCEL_INT1_ENABLED) {
++ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
++ NULL,
++ lis331dlh_intel_qrk_threshold_event_handler,
++ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
++ "lis331dlh_intel_qrk_threshold",
++ indio_dev);
++ if (likely(err == 0)) {
++ sdata->sensor->drdy_irq.ig1.en_mask =
++ QRK_ACCEL_INT1_ENABLED;
++ err = sdata->tf->write_byte(
++ &sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_DURATION_ADDR, 1);
++ }
++ } else {
++ free_irq(sdata->get_irq_data_ready(indio_dev), indio_dev);
++ sdata->sensor->drdy_irq.ig1.en_mask = QRK_ACCEL_INT1_DISABLED;
++ }
++
++ return err;
++}
++
++static int lis331dlh_intel_qrk_read_event_config(
++ struct iio_dev *indio_dev,
++ u64 event_code)
++{
++ int err = 0;
++ u8 data, mask;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_CFG_ADDR,
++ &data);
++
++ mask = 1 << ((IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code) << 1) - 1);
++
++ return !!(data & mask);
++}
++
++static int lis331dlh_intel_qrk_write_event_config(
++ struct iio_dev *indio_dev,
++ u64 event_code,
++ int state)
++{
++ int err;
++ u8 data;
++ u8 mask;
++
++ bool new_int_state;
++
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++ mask = 1 << ((IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code) << 1) - 1);
++
++ err = st_sensors_write_data_with_mask(indio_dev,
++ ST_ACCEL_2_INT1_CFG_ADDR,
++ mask, state);
++ if (unlikely(err < 0))
++ goto write_event_err;
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_CFG_ADDR, &data);
++ if (unlikely(err < 0))
++ goto write_event_err;
++
++ new_int_state = data & (ST_ACCEL_2_INT_CFG_XHIE_EN |
++ ST_ACCEL_2_INT_CFG_YHIE_EN |
++ ST_ACCEL_2_INT_CFG_ZHIE_EN);
++ err = lis331dlh_intel_qrk_configure_threshold_interrupt(
++ indio_dev, new_int_state);
++
++write_event_err:
++ return err;
++}
++
++/* Configure the INT2 pin to fire an interrupt on a threshold high event. INT2
++ * should be wired to a suspend well IRQ to wake up the host.
++ */
++static int lis331dlh_intel_qrk_enable_wakeup_interrupt(
++ struct iio_dev *indio_dev)
++{
++ int err = 0;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_THRESH_ADDR,
++ QRK_ACCEL_INT2_WAKEUP_THRESH_VAL);
++ if (unlikely(err < 0))
++ goto enable_wakeup_int_err;
++
++ /* Latch interrupt request on INT2 */
++ err = st_sensors_write_data_with_mask(
++ indio_dev, ST_ACCEL_2_DRDY_IRQ_ADDR,
++ ST_ACCEL_2_INT_LIR_MASK, 1);
++ if (unlikely(err < 0))
++ goto enable_wakeup_int_err;
++
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_DURATION_ADDR, 0);
++ if (unlikely(err < 0))
++ goto enable_wakeup_int_err;
++
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_CFG_ADDR,
++ ST_ACCEL_2_INT_CFG_XHIE_EN |
++ ST_ACCEL_2_INT_CFG_YHIE_EN);
++ if (unlikely(err < 0))
++ goto enable_wakeup_int_err;
++
++ /* Clean ST_ACCEL_2_INT2_SRC */
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_SRC_ADDR,
++ &data);
++
++enable_wakeup_int_err:
++ return err;
++}
++
++static int lis331dlh_intel_qrk_disable_wakeup_interrupt(
++ struct iio_dev *indio_dev)
++{
++ int err = 0;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_CFG_ADDR,
++ 0);
++ if (unlikely(err < 0))
++ goto disable_wakeup_int_err;
++
++ /* Clean ST_ACCEL_2_INT2_SRC */
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_SRC_ADDR,
++ &data);
++ if (unlikely(err < 0))
++ goto disable_wakeup_int_err;
++
++disable_wakeup_int_err:
++ return err;
++}
++
++static int lis331dlh_intel_qrk_handle_wakeup_interrupt(
++ struct iio_dev *indio_dev)
++{
++ int err;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++ s64 timestamp = iio_get_time_ns();
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_SRC_ADDR,
++ &data);
++ if (unlikely(err < 0))
++ goto handle_wakeup_int_err;
++
++ if (data & ST_ACCEL_2_INT_IA_MASK) {
++ iio_push_event(indio_dev,
++ IIO_MOD_EVENT_CODE(IIO_ACCEL,
++ 0,
++ IIO_MOD_X_OR_Y_OR_Z,
++ IIO_EV_TYPE_THRESH,
++ IIO_EV_DIR_EITHER),
++ timestamp);
++ }
++
++handle_wakeup_int_err:
++ return err;
++}
++
++static const struct iio_info accel_info = {
++ .driver_module = THIS_MODULE,
++ .attrs = &lis331dlh_intel_qrk_attribute_group,
++ .read_raw = &lis331dlh_intel_qrk_read_raw,
++ .write_raw = &lis331dlh_intel_qrk_write_raw,
++ .read_event_config = &lis331dlh_intel_qrk_read_event_config,
++ .write_event_config = &lis331dlh_intel_qrk_write_event_config,
++ .read_event_value = &lis331dlh_intel_qrk_read_event_value,
++ .write_event_value = &lis331dlh_intel_qrk_write_event_value,
++};
++
++static const struct iio_chan_spec st_accel_12bit_channels[] = {
++ QRK_ACCEL_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
++ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
++ QRK_ACCEL_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
++ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
++ QRK_ACCEL_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
++ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
++ IIO_CHAN_SOFT_TIMESTAMP(3)
++};
++
++static struct st_sensors lis331dlh_intel_qrk_sensor = {
++ .wai = ST_ACCEL_2_WAI_EXP,
++ .sensors_supported = {
++ [0] = "lis331dlh_qrk",
++ },
++ .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
++ .odr = {
++ .addr = ST_ACCEL_2_ODR_ADDR,
++ .mask = ST_ACCEL_2_ODR_MASK,
++ .odr_avl = {
++ { 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
++ { 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
++ { 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
++ { 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
++ },
++ },
++ .pw = {
++ .addr = ST_ACCEL_2_PW_ADDR,
++ .mask = ST_ACCEL_2_PW_MASK,
++ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
++ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
++ },
++ .enable_axis = {
++ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
++ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
++ },
++ .fs = {
++ .addr = ST_ACCEL_2_FS_ADDR,
++ .mask = ST_ACCEL_2_FS_MASK,
++ .fs_avl = {
++ [0] = {
++ .num = ST_ACCEL_FS_AVL_2G,
++ .value = ST_ACCEL_2_FS_AVL_2_VAL,
++ .gain = ST_ACCEL_2_FS_AVL_2_GAIN,
++ },
++ [1] = {
++ .num = ST_ACCEL_FS_AVL_4G,
++ .value = ST_ACCEL_2_FS_AVL_4_VAL,
++ .gain = ST_ACCEL_2_FS_AVL_4_GAIN,
++ },
++ [2] = {
++ .num = ST_ACCEL_FS_AVL_8G,
++ .value = ST_ACCEL_2_FS_AVL_8_VAL,
++ .gain = ST_ACCEL_2_FS_AVL_8_GAIN,
++ },
++ },
++ },
++ .bdu = {
++ .addr = ST_ACCEL_2_BDU_ADDR,
++ .mask = ST_ACCEL_2_BDU_MASK,
++ },
++ .drdy_irq = {
++ .addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
++ .mask = ST_ACCEL_2_DRDY_IRQ_MASK,
++ },
++ .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
++ .bootime = 2,
++};
++
++static int lis331dlh_intel_qrk_probe(
++ struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct iio_dev *indio_dev;
++ struct st_sensor_data *adata;
++ struct lis331dlh_intel_qrk_platform_data *pdata;
++ int ret = 0;
++
++ indio_dev = iio_device_alloc(sizeof(*adata));
++ if (unlikely(indio_dev == NULL)) {
++ ret = -ENOMEM;
++ goto iio_device_alloc_error;
++ }
++
++ i2c_set_clientdata(client, indio_dev);
++ indio_dev->dev.parent = &client->dev;
++ indio_dev->name = client->name;
++
++ adata = iio_priv(indio_dev);
++ adata->dev = &client->dev;
++
++ pdata = client->dev.platform_data;
++ if (unlikely(!pdata)) {
++ pr_err("No platform data provided\n");
++ goto lis331dlh_intel_qrk_init_err;
++ }
++
++ ret = gpio_to_irq(pdata->irq1_pin);
++ if (unlikely(ret < 0)) {
++ pr_err(
++ "Failed to obtain valid IRQ for GPIO %d, "
++ "gpio_to_irq returned %d\n",
++ pdata->irq1_pin, ret);
++ goto lis331dlh_intel_qrk_init_err;
++ }
++ to_i2c_client(adata->dev)->irq = ret;
++
++ st_sensors_i2c_configure(indio_dev, client, adata);
++
++ indio_dev->modes = INDIO_DIRECT_MODE;
++ indio_dev->info = &accel_info;
++
++ ret = st_sensors_check_device_support(indio_dev,
++ 1, &lis331dlh_intel_qrk_sensor);
++ if (unlikely(ret < 0))
++ goto lis331dlh_intel_qrk_init_err;
++
++ indio_dev->channels = adata->sensor->ch;
++ indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
++
++ adata->multiread_bit = adata->sensor->multi_read_bit;
++ adata->current_fullscale = (struct st_sensor_fullscale_avl *)
++ &adata->sensor->fs.fs_avl[0];
++ adata->odr = adata->sensor->odr.odr_avl[0].hz;
++
++ adata->sensor->drdy_irq.ig1.en_mask = QRK_ACCEL_INT1_DISABLED;
++
++ ret = st_sensors_init_sensor(indio_dev);
++ if (unlikely(ret < 0))
++ goto lis331dlh_intel_qrk_init_err;
++
++ ret = st_sensors_set_enable(indio_dev, true);
++ if (unlikely(ret < 0))
++ goto lis331dlh_intel_qrk_init_err;
++
++ ret = iio_device_register(indio_dev);
++ if (unlikely(ret))
++ goto lis331dlh_intel_qrk_init_err;
++
++ return 0;
++
++lis331dlh_intel_qrk_init_err:
++ iio_device_free(indio_dev);
++iio_device_alloc_error:
++ return ret;
++}
++
++static int lis331dlh_intel_qrk_remove(
++ struct i2c_client *client)
++{
++ struct iio_dev *indio_dev = i2c_get_clientdata(client);
++ struct st_sensor_data *adata = iio_priv(indio_dev);
++
++ st_sensors_set_enable(indio_dev, false);
++
++ if (adata->sensor->drdy_irq.ig1.en_mask == QRK_ACCEL_INT1_ENABLED)
++ free_irq(adata->get_irq_data_ready(indio_dev), indio_dev);
++
++ iio_device_unregister(indio_dev);
++
++ iio_device_free(indio_dev);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int lis331dlh_intel_qrk_suspend(
++ struct device *dev)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ lis331dlh_intel_qrk_enable_wakeup_interrupt(indio_dev);
++
++ return 0;
++}
++
++static int lis331dlh_intel_qrk_resume(
++ struct device *dev)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ lis331dlh_intel_qrk_handle_wakeup_interrupt(indio_dev);
++ lis331dlh_intel_qrk_disable_wakeup_interrupt(indio_dev);
++
++ return 0;
++}
++
++static const struct dev_pm_ops lis331dlh_intel_qrk_pm_ops = {
++ .suspend = lis331dlh_intel_qrk_suspend,
++ .resume = lis331dlh_intel_qrk_resume,
++};
++
++#define LIS331DLH_INTEL_QRK_PM_OPS (&lis331dlh_intel_qrk_pm_ops)
++#else
++#define LIS331DLH_INTEL_QRK_PM_OPS NULL
++#endif
++
++static const struct i2c_device_id lis331dlh_intel_qrk_id_table[] = {
++ { "lis331dlh_qrk" },
++ {},
++};
++MODULE_DEVICE_TABLE(i2c, lis331dlh_intel_qrk_id_table);
++
++static struct i2c_driver lis331dlh_intel_qrk_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "lis331dlh_qrk",
++ .pm = LIS331DLH_INTEL_QRK_PM_OPS,
++ },
++ .probe = lis331dlh_intel_qrk_probe,
++ .remove = lis331dlh_intel_qrk_remove,
++ .id_table = lis331dlh_intel_qrk_id_table,
++};
++
++module_i2c_driver(lis331dlh_intel_qrk_driver);
++
++MODULE_AUTHOR("Wojciech Ziemba <wojciech.ziemba@emutex.com>");
++MODULE_DESCRIPTION("STMicroelectronics LIS331DLH accelerometer i2c driver for Intel Quark platform");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
+index ed45ee5..64bcb14 100644
+--- a/drivers/iio/common/Kconfig
++++ b/drivers/iio/common/Kconfig
+@@ -3,3 +3,4 @@
+ #
+
+ source "drivers/iio/common/hid-sensors/Kconfig"
++source "drivers/iio/common/st_sensors/Kconfig"
+\ No newline at end of file
+diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
+index 8158400..c2352be 100644
+--- a/drivers/iio/common/Makefile
++++ b/drivers/iio/common/Makefile
+@@ -7,3 +7,4 @@
+ #
+
+ obj-y += hid-sensors/
++obj-y += st_sensors/
+diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig
+new file mode 100644
+index 0000000..865f1ca
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/Kconfig
+@@ -0,0 +1,14 @@
++#
++# STMicroelectronics sensors common library
++#
++
++config IIO_ST_SENSORS_I2C
++ tristate
++
++config IIO_ST_SENSORS_SPI
++ tristate
++
++config IIO_ST_SENSORS_CORE
++ tristate
++ select IIO_ST_SENSORS_I2C if I2C
++ select IIO_ST_SENSORS_SPI if SPI_MASTER
+diff --git a/drivers/iio/common/st_sensors/Makefile b/drivers/iio/common/st_sensors/Makefile
+new file mode 100644
+index 0000000..9f3e24f
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the STMicroelectronics sensor common modules.
++#
++
++obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o
++obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o
++obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o
++st_sensors-y := st_sensors_core.o
++st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o
++st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o
+diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
+new file mode 100644
+index 0000000..a269b7d
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
+@@ -0,0 +1,115 @@
++/*
++ * STMicroelectronics sensors buffer library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/trigger.h>
++#include <linux/interrupt.h>
++#include <linux/iio/buffer.h>
++#include <linux/iio/trigger_consumer.h>
++#include <linux/iio/triggered_buffer.h>
++#include <linux/irqreturn.h>
++
++#include <linux/iio/common/st_sensors.h>
++
++
++int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
++{
++ int i, n = 0, len;
++ u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS];
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
++ if (test_bit(i, indio_dev->active_scan_mask)) {
++ addr[n] = indio_dev->channels[i].address;
++ n++;
++ }
++ }
++ switch (n) {
++ case 1:
++ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
++ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf,
++ sdata->multiread_bit);
++ break;
++ case 2:
++ if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) {
++ len = sdata->tf->read_multiple_byte(&sdata->tb,
++ sdata->dev, addr[0],
++ ST_SENSORS_BYTE_FOR_CHANNEL*n,
++ buf, sdata->multiread_bit);
++ } else {
++ u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL*
++ ST_SENSORS_NUMBER_DATA_CHANNELS];
++ len = sdata->tf->read_multiple_byte(&sdata->tb,
++ sdata->dev, addr[0],
++ ST_SENSORS_BYTE_FOR_CHANNEL*
++ ST_SENSORS_NUMBER_DATA_CHANNELS,
++ rx_array, sdata->multiread_bit);
++ if (len < 0)
++ goto read_data_channels_error;
++
++ for (i = 0; n + i < sizeof(rx_array); i++){
++ if (i < n)
++ buf[i] = rx_array[i];
++ else
++ buf[i] = rx_array[n + i];
++ }
++ len = ST_SENSORS_BYTE_FOR_CHANNEL*n;
++ }
++ break;
++ case 3:
++ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
++ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL*
++ ST_SENSORS_NUMBER_DATA_CHANNELS,
++ buf, sdata->multiread_bit);
++ break;
++ default:
++ len = -EINVAL;
++ goto read_data_channels_error;
++ }
++ if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) {
++ len = -EIO;
++ goto read_data_channels_error;
++ }
++
++read_data_channels_error:
++ return len;
++}
++EXPORT_SYMBOL(st_sensors_get_buffer_element);
++
++irqreturn_t st_sensors_trigger_handler(int irq, void *p)
++{
++ int len;
++ struct iio_poll_func *pf = p;
++ struct iio_dev *indio_dev = pf->indio_dev;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
++ if (len < 0)
++ goto st_sensors_get_buffer_element_error;
++
++ if (indio_dev->scan_timestamp)
++ *(s64 *)((u8 *)sdata->buffer_data +
++ ALIGN(len, sizeof(s64))) = pf->timestamp;
++
++ iio_push_to_buffers(indio_dev, sdata->buffer_data);
++
++st_sensors_get_buffer_element_error:
++ iio_trigger_notify_done(indio_dev->trig);
++
++ return IRQ_HANDLED;
++}
++EXPORT_SYMBOL(st_sensors_trigger_handler);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
+new file mode 100644
+index 0000000..945a55b
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_core.c
+@@ -0,0 +1,447 @@
++/*
++ * STMicroelectronics sensors core library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/iio/iio.h>
++#include <asm/unaligned.h>
++
++#include <linux/iio/common/st_sensors.h>
++
++
++#define ST_SENSORS_WAI_ADDRESS 0x0f
++
++int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
++ u8 reg_addr, u8 mask, u8 data)
++{
++ int err;
++ u8 new_data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
++ if (err < 0)
++ goto st_sensors_write_data_with_mask_error;
++
++ new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
++
++st_sensors_write_data_with_mask_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_write_data_with_mask);
++
++static int st_sensors_match_odr(struct st_sensors *sensor,
++ unsigned int odr, struct st_sensor_odr_avl *odr_out)
++{
++ int i, ret = -EINVAL;
++
++ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
++ if (sensor->odr.odr_avl[i].hz == 0)
++ goto st_sensors_match_odr_error;
++
++ if (sensor->odr.odr_avl[i].hz == odr) {
++ odr_out->hz = sensor->odr.odr_avl[i].hz;
++ odr_out->value = sensor->odr.odr_avl[i].value;
++ ret = 0;
++ break;
++ }
++ }
++
++st_sensors_match_odr_error:
++ return ret;
++}
++
++int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
++{
++ int err;
++ struct st_sensor_odr_avl odr_out = {0, 0};
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
++ if (err < 0)
++ goto st_sensors_match_odr_error;
++
++ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
++ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
++ if (sdata->enabled == true) {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->odr.addr,
++ sdata->sensor->odr.mask,
++ odr_out.value);
++ } else {
++ err = 0;
++ }
++ } else {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->odr.addr, sdata->sensor->odr.mask,
++ odr_out.value);
++ }
++ if (err >= 0)
++ sdata->odr = odr_out.hz;
++
++st_sensors_match_odr_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_odr);
++
++static int st_sensors_match_fs(struct st_sensors *sensor,
++ unsigned int fs, int *index_fs_avl)
++{
++ int i, ret = -EINVAL;
++
++ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
++ if (sensor->fs.fs_avl[i].num == 0)
++ goto st_sensors_match_odr_error;
++
++ if (sensor->fs.fs_avl[i].num == fs) {
++ *index_fs_avl = i;
++ ret = 0;
++ break;
++ }
++ }
++
++st_sensors_match_odr_error:
++ return ret;
++}
++
++static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
++{
++ int err, i = 0;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = st_sensors_match_fs(sdata->sensor, fs, &i);
++ if (err < 0)
++ goto st_accel_set_fullscale_error;
++
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->fs.addr,
++ sdata->sensor->fs.mask,
++ sdata->sensor->fs.fs_avl[i].value);
++ if (err < 0)
++ goto st_accel_set_fullscale_error;
++
++ sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
++ &sdata->sensor->fs.fs_avl[i];
++ return err;
++
++st_accel_set_fullscale_error:
++ dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
++ return err;
++}
++
++int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
++{
++ u8 tmp_value;
++ int err = -EINVAL;
++ bool found = false;
++ struct st_sensor_odr_avl odr_out = {0, 0};
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ if (enable) {
++ tmp_value = sdata->sensor->pw.value_on;
++ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
++ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
++ err = st_sensors_match_odr(sdata->sensor,
++ sdata->odr, &odr_out);
++ if (err < 0)
++ goto set_enable_error;
++ tmp_value = odr_out.value;
++ found = true;
++ }
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->pw.addr,
++ sdata->sensor->pw.mask, tmp_value);
++ if (err < 0)
++ goto set_enable_error;
++
++ sdata->enabled = true;
++
++ if (found)
++ sdata->odr = odr_out.hz;
++ } else {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->pw.addr,
++ sdata->sensor->pw.mask,
++ sdata->sensor->pw.value_off);
++ if (err < 0)
++ goto set_enable_error;
++
++ sdata->enabled = false;
++ }
++
++set_enable_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_enable);
++
++int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ return st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->enable_axis.addr,
++ sdata->sensor->enable_axis.mask, axis_enable);
++}
++EXPORT_SYMBOL(st_sensors_set_axis_enable);
++
++int st_sensors_init_sensor(struct iio_dev *indio_dev)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_init(&sdata->tb.buf_lock);
++
++ err = st_sensors_set_enable(indio_dev, false);
++ if (err < 0)
++ goto init_error;
++
++ err = st_sensors_set_fullscale(indio_dev,
++ sdata->current_fullscale->num);
++ if (err < 0)
++ goto init_error;
++
++ err = st_sensors_set_odr(indio_dev, sdata->odr);
++ if (err < 0)
++ goto init_error;
++
++ /* set BDU */
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
++ if (err < 0)
++ goto init_error;
++
++ err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
++
++init_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_init_sensor);
++
++int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ /* Enable/Disable the interrupt generator 1. */
++ if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->drdy_irq.ig1.en_addr,
++ sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
++ if (err < 0)
++ goto st_accel_set_dataready_irq_error;
++ }
++
++ /* Enable/Disable the interrupt generator for data ready. */
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->drdy_irq.addr,
++ sdata->sensor->drdy_irq.mask, (int)enable);
++
++st_accel_set_dataready_irq_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_dataready_irq);
++
++int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
++{
++ int err = -EINVAL, i;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
++ if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
++ (sdata->sensor->fs.fs_avl[i].gain != 0)) {
++ err = 0;
++ break;
++ }
++ }
++ if (err < 0)
++ goto st_sensors_match_scale_error;
++
++ err = st_sensors_set_fullscale(indio_dev,
++ sdata->sensor->fs.fs_avl[i].num);
++
++st_sensors_match_scale_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
++
++int st_sensors_read_axis_data(struct iio_dev *indio_dev,
++ u8 ch_addr, int *data)
++{
++ int err;
++ u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL];
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
++ ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL,
++ outdata, sdata->multiread_bit);
++ if (err < 0)
++ goto read_error;
++
++ *data = (s16)get_unaligned_le16(outdata);
++
++read_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_read_axis_data);
++
++int st_sensors_read_info_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *ch, int *val)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ err = -EBUSY;
++ goto read_error;
++ } else {
++ err = st_sensors_set_enable(indio_dev, true);
++ if (err < 0)
++ goto read_error;
++
++ msleep((sdata->sensor->bootime * 1000) / sdata->odr);
++ err = st_sensors_read_axis_data(indio_dev, ch->address, val);
++ if (err < 0)
++ goto read_error;
++
++ *val = *val >> ch->scan_type.shift;
++ }
++ mutex_unlock(&indio_dev->mlock);
++
++ return err;
++
++read_error:
++ mutex_unlock(&indio_dev->mlock);
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_read_info_raw);
++
++int st_sensors_check_device_support(struct iio_dev *indio_dev,
++ int num_sensors_list, const struct st_sensors *sensors)
++{
++ u8 wai;
++ int i, n, err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
++ if (err < 0) {
++ dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
++ goto read_wai_error;
++ }
++
++ for (i = 0; i < num_sensors_list; i++) {
++ if (sensors[i].wai == wai)
++ break;
++ }
++ if (i == num_sensors_list)
++ goto device_not_supported;
++
++ for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
++ if (strcmp(indio_dev->name,
++ &sensors[i].sensors_supported[n][0]) == 0)
++ break;
++ }
++ if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
++ dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
++ goto sensor_name_mismatch;
++ }
++
++ sdata->sensor = (struct st_sensors *)&sensors[i];
++
++ return i;
++
++device_not_supported:
++ dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
++sensor_name_mismatch:
++ err = -ENODEV;
++read_wai_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_check_device_support);
++
++ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
++
++ return sprintf(buf, "%d\n", adata->odr);
++}
++EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
++
++ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int err;
++ unsigned int odr;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ err = kstrtoint(buf, 10, &odr);
++ if (err < 0)
++ goto conversion_error;
++
++ mutex_lock(&indio_dev->mlock);
++ err = st_sensors_set_odr(indio_dev, odr);
++ mutex_unlock(&indio_dev->mlock);
++
++conversion_error:
++ return err < 0 ? err : size;
++}
++EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
++
++ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int i, len = 0;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_lock(&indio_dev->mlock);
++ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
++ if (sdata->sensor->odr.odr_avl[i].hz == 0)
++ break;
++
++ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
++ sdata->sensor->odr.odr_avl[i].hz);
++ }
++ mutex_unlock(&indio_dev->mlock);
++ buf[len - 1] = '\n';
++
++ return len;
++}
++EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
++
++ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int i, len = 0;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_lock(&indio_dev->mlock);
++ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
++ if (sdata->sensor->fs.fs_avl[i].num == 0)
++ break;
++
++ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
++ sdata->sensor->fs.fs_avl[i].gain);
++ }
++ mutex_unlock(&indio_dev->mlock);
++ buf[len - 1] = '\n';
++
++ return len;
++}
++EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
+new file mode 100644
+index 0000000..38af944
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
+@@ -0,0 +1,81 @@
++/*
++ * STMicroelectronics sensors i2c library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++
++#include <linux/iio/common/st_sensors_i2c.h>
++
++
++#define ST_SENSORS_I2C_MULTIREAD 0x80
++
++static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ return to_i2c_client(sdata->dev)->irq;
++}
++
++static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 *res_byte)
++{
++ int err;
++
++ err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
++ if (err < 0)
++ goto st_accel_i2c_read_byte_error;
++
++ *res_byte = err & 0xff;
++
++st_accel_i2c_read_byte_error:
++ return err < 0 ? err : 0;
++}
++
++static int st_sensors_i2c_read_multiple_byte(
++ struct st_sensor_transfer_buffer *tb, struct device *dev,
++ u8 reg_addr, int len, u8 *data, bool multiread_bit)
++{
++ if (multiread_bit)
++ reg_addr |= ST_SENSORS_I2C_MULTIREAD;
++
++ return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
++ reg_addr, len, data);
++}
++
++static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 data)
++{
++ return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
++}
++
++static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
++ .read_byte = st_sensors_i2c_read_byte,
++ .write_byte = st_sensors_i2c_write_byte,
++ .read_multiple_byte = st_sensors_i2c_read_multiple_byte,
++};
++
++void st_sensors_i2c_configure(struct iio_dev *indio_dev,
++ struct i2c_client *client, struct st_sensor_data *sdata)
++{
++ i2c_set_clientdata(client, indio_dev);
++
++ indio_dev->dev.parent = &client->dev;
++ indio_dev->name = client->name;
++
++ sdata->tf = &st_sensors_tf_i2c;
++ sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
++}
++EXPORT_SYMBOL(st_sensors_i2c_configure);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
+new file mode 100644
+index 0000000..f0aa2f1
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
+@@ -0,0 +1,128 @@
++/*
++ * STMicroelectronics sensors spi library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++
++#include <linux/iio/common/st_sensors_spi.h>
++
++
++#define ST_SENSORS_SPI_MULTIREAD 0xc0
++#define ST_SENSORS_SPI_READ 0x80
++
++static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ return to_spi_device(sdata->dev)->irq;
++}
++
++static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
++{
++ struct spi_message msg;
++ int err;
++
++ struct spi_transfer xfers[] = {
++ {
++ .tx_buf = tb->tx_buf,
++ .bits_per_word = 8,
++ .len = 1,
++ },
++ {
++ .rx_buf = tb->rx_buf,
++ .bits_per_word = 8,
++ .len = len,
++ }
++ };
++
++ mutex_lock(&tb->buf_lock);
++ if ((multiread_bit) && (len > 1))
++ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
++ else
++ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
++
++ spi_message_init(&msg);
++ spi_message_add_tail(&xfers[0], &msg);
++ spi_message_add_tail(&xfers[1], &msg);
++ err = spi_sync(to_spi_device(dev), &msg);
++ if (err)
++ goto acc_spi_read_error;
++
++ memcpy(data, tb->rx_buf, len*sizeof(u8));
++ mutex_unlock(&tb->buf_lock);
++ return len;
++
++acc_spi_read_error:
++ mutex_unlock(&tb->buf_lock);
++ return err;
++}
++
++static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 *res_byte)
++{
++ return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
++}
++
++static int st_sensors_spi_read_multiple_byte(
++ struct st_sensor_transfer_buffer *tb, struct device *dev,
++ u8 reg_addr, int len, u8 *data, bool multiread_bit)
++{
++ return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
++}
++
++static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 data)
++{
++ struct spi_message msg;
++ int err;
++
++ struct spi_transfer xfers = {
++ .tx_buf = tb->tx_buf,
++ .bits_per_word = 8,
++ .len = 2,
++ };
++
++ mutex_lock(&tb->buf_lock);
++ tb->tx_buf[0] = reg_addr;
++ tb->tx_buf[1] = data;
++
++ spi_message_init(&msg);
++ spi_message_add_tail(&xfers, &msg);
++ err = spi_sync(to_spi_device(dev), &msg);
++ mutex_unlock(&tb->buf_lock);
++
++ return err;
++}
++
++static const struct st_sensor_transfer_function st_sensors_tf_spi = {
++ .read_byte = st_sensors_spi_read_byte,
++ .write_byte = st_sensors_spi_write_byte,
++ .read_multiple_byte = st_sensors_spi_read_multiple_byte,
++};
++
++void st_sensors_spi_configure(struct iio_dev *indio_dev,
++ struct spi_device *spi, struct st_sensor_data *sdata)
++{
++ spi_set_drvdata(spi, indio_dev);
++
++ indio_dev->dev.parent = &spi->dev;
++ indio_dev->name = spi->modalias;
++
++ sdata->tf = &st_sensors_tf_spi;
++ sdata->get_irq_data_ready = st_sensors_spi_get_irq;
++}
++EXPORT_SYMBOL(st_sensors_spi_configure);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
+new file mode 100644
+index 0000000..139ed03
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
+@@ -0,0 +1,77 @@
++/*
++ * STMicroelectronics sensors trigger library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/trigger.h>
++#include <linux/interrupt.h>
++
++#include <linux/iio/common/st_sensors.h>
++
++
++int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
++ const struct iio_trigger_ops *trigger_ops)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
++ if (sdata->trig == NULL) {
++ err = -ENOMEM;
++ dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
++ goto iio_trigger_alloc_error;
++ }
++
++ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
++ iio_trigger_generic_data_rdy_poll,
++ NULL,
++ IRQF_TRIGGER_RISING,
++ sdata->trig->name,
++ sdata->trig);
++ if (err)
++ goto request_irq_error;
++
++ sdata->trig->private_data = indio_dev;
++ sdata->trig->ops = trigger_ops;
++ sdata->trig->dev.parent = sdata->dev;
++
++ err = iio_trigger_register(sdata->trig);
++ if (err < 0) {
++ dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
++ goto iio_trigger_register_error;
++ }
++ indio_dev->trig = sdata->trig;
++
++ return 0;
++
++iio_trigger_register_error:
++ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
++request_irq_error:
++ iio_trigger_free(sdata->trig);
++iio_trigger_alloc_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_allocate_trigger);
++
++void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ iio_trigger_unregister(sdata->trig);
++ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
++ iio_trigger_free(sdata->trig);
++}
++EXPORT_SYMBOL(st_sensors_deallocate_trigger);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
+index aaadd32..7b8d510 100644
+--- a/drivers/iio/industrialio-buffer.c
++++ b/drivers/iio/industrialio-buffer.c
+@@ -119,8 +119,8 @@ static ssize_t iio_scan_el_show(struct device *dev,
+ int ret;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+
+- ret = test_bit(to_iio_dev_attr(attr)->address,
+- indio_dev->buffer->scan_mask);
++ ret = abs(test_bit(to_iio_dev_attr(attr)->address,
++ indio_dev->buffer->scan_mask));
+
+ return sprintf(buf, "%d\n", ret);
+ }
+@@ -762,7 +762,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev,
+ if (!buffer->scan_mask)
+ return 0;
+
+- return test_bit(bit, buffer->scan_mask);
++ return abs(test_bit(bit, buffer->scan_mask));
+ };
+ EXPORT_SYMBOL_GPL(iio_scan_mask_query);
+
+diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
+new file mode 100644
+index 0000000..56d0495
+--- /dev/null
++++ b/include/linux/iio/common/st_sensors.h
+@@ -0,0 +1,289 @@
++/*
++ * STMicroelectronics sensors library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#ifndef ST_SENSORS_H
++#define ST_SENSORS_H
++
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <linux/irqreturn.h>
++#include <linux/iio/trigger.h>
++
++#define ST_SENSORS_TX_MAX_LENGTH 2
++#define ST_SENSORS_RX_MAX_LENGTH 6
++
++#define ST_SENSORS_ODR_LIST_MAX 10
++#define ST_SENSORS_FULLSCALE_AVL_MAX 10
++
++#define ST_SENSORS_NUMBER_ALL_CHANNELS 4
++#define ST_SENSORS_NUMBER_DATA_CHANNELS 3
++#define ST_SENSORS_ENABLE_ALL_AXIS 0x07
++#define ST_SENSORS_BYTE_FOR_CHANNEL 2
++#define ST_SENSORS_SCAN_X 0
++#define ST_SENSORS_SCAN_Y 1
++#define ST_SENSORS_SCAN_Z 2
++#define ST_SENSORS_DEFAULT_12_REALBITS 12
++#define ST_SENSORS_DEFAULT_16_REALBITS 16
++#define ST_SENSORS_DEFAULT_POWER_ON_VALUE 0x01
++#define ST_SENSORS_DEFAULT_POWER_OFF_VALUE 0x00
++#define ST_SENSORS_DEFAULT_WAI_ADDRESS 0x0f
++#define ST_SENSORS_DEFAULT_AXIS_ADDR 0x20
++#define ST_SENSORS_DEFAULT_AXIS_MASK 0x07
++#define ST_SENSORS_DEFAULT_AXIS_N_BIT 3
++
++#define ST_SENSORS_MAX_NAME 17
++#define ST_SENSORS_MAX_4WAI 7
++
++#define ST_SENSORS_LSM_CHANNELS(device_type, index, mod, endian, bits, addr) \
++{ \
++ .type = device_type, \
++ .modified = 1, \
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
++ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
++ .scan_index = index, \
++ .channel2 = mod, \
++ .address = addr, \
++ .scan_type = { \
++ .sign = 's', \
++ .realbits = bits, \
++ .shift = 16 - bits, \
++ .storagebits = 16, \
++ .endianness = endian, \
++ }, \
++}
++
++#define ST_SENSOR_DEV_ATTR_SAMP_FREQ() \
++ IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, \
++ st_sensors_sysfs_get_sampling_frequency, \
++ st_sensors_sysfs_set_sampling_frequency)
++
++#define ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL() \
++ IIO_DEV_ATTR_SAMP_FREQ_AVAIL( \
++ st_sensors_sysfs_sampling_frequency_avail)
++
++#define ST_SENSORS_DEV_ATTR_SCALE_AVAIL(name) \
++ IIO_DEVICE_ATTR(name, S_IRUGO, \
++ st_sensors_sysfs_scale_avail, NULL , 0);
++
++struct st_sensor_odr_avl {
++ unsigned int hz;
++ u8 value;
++};
++
++struct st_sensor_odr {
++ u8 addr;
++ u8 mask;
++ struct st_sensor_odr_avl odr_avl[ST_SENSORS_ODR_LIST_MAX];
++};
++
++struct st_sensor_power {
++ u8 addr;
++ u8 mask;
++ u8 value_off;
++ u8 value_on;
++};
++
++struct st_sensor_axis {
++ u8 addr;
++ u8 mask;
++};
++
++struct st_sensor_fullscale_avl {
++ unsigned int num;
++ u8 value;
++ unsigned int gain;
++ unsigned int gain2;
++};
++
++struct st_sensor_fullscale {
++ u8 addr;
++ u8 mask;
++ struct st_sensor_fullscale_avl fs_avl[ST_SENSORS_FULLSCALE_AVL_MAX];
++};
++
++/**
++ * struct st_sensor_bdu - ST sensor device block data update
++ * @addr: address of the register.
++ * @mask: mask to write the block data update flag.
++ */
++struct st_sensor_bdu {
++ u8 addr;
++ u8 mask;
++};
++
++/**
++ * struct st_sensor_data_ready_irq - ST sensor device data-ready interrupt
++ * @addr: address of the register.
++ * @mask: mask to write the on/off value.
++ * struct ig1 - represents the Interrupt Generator 1 of sensors.
++ * @en_addr: address of the enable ig1 register.
++ * @en_mask: mask to write the on/off value for enable.
++ */
++struct st_sensor_data_ready_irq {
++ u8 addr;
++ u8 mask;
++ struct {
++ u8 en_addr;
++ u8 en_mask;
++ } ig1;
++};
++
++/**
++ * struct st_sensor_transfer_buffer - ST sensor device I/O buffer
++ * @buf_lock: Mutex to protect rx and tx buffers.
++ * @tx_buf: Buffer used by SPI transfer function to send data to the sensors.
++ * This buffer is used to avoid DMA not-aligned issue.
++ * @rx_buf: Buffer used by SPI transfer to receive data from sensors.
++ * This buffer is used to avoid DMA not-aligned issue.
++ */
++struct st_sensor_transfer_buffer {
++ struct mutex buf_lock;
++ u8 rx_buf[ST_SENSORS_RX_MAX_LENGTH];
++ u8 tx_buf[ST_SENSORS_TX_MAX_LENGTH] ____cacheline_aligned;
++};
++
++/**
++ * struct st_sensor_transfer_function - ST sensor device I/O function
++ * @read_byte: Function used to read one byte.
++ * @write_byte: Function used to write one byte.
++ * @read_multiple_byte: Function used to read multiple byte.
++ */
++struct st_sensor_transfer_function {
++ int (*read_byte) (struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 *res_byte);
++ int (*write_byte) (struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 data);
++ int (*read_multiple_byte) (struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, int len, u8 *data,
++ bool multiread_bit);
++};
++
++/**
++ * struct st_sensors - ST sensors list
++ * @wai: Contents of WhoAmI register.
++ * @sensors_supported: List of supported sensors by struct itself.
++ * @ch: IIO channels for the sensor.
++ * @odr: Output data rate register and ODR list available.
++ * @pw: Power register of the sensor.
++ * @enable_axis: Enable one or more axis of the sensor.
++ * @fs: Full scale register and full scale list available.
++ * @bdu: Block data update register.
++ * @drdy_irq: Data ready register of the sensor.
++ * @multi_read_bit: Use or not particular bit for [I2C/SPI] multi-read.
++ * @bootime: samples to discard when sensor passing from power-down to power-up.
++ */
++struct st_sensors {
++ u8 wai;
++ char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME];
++ struct iio_chan_spec *ch;
++ struct st_sensor_odr odr;
++ struct st_sensor_power pw;
++ struct st_sensor_axis enable_axis;
++ struct st_sensor_fullscale fs;
++ struct st_sensor_bdu bdu;
++ struct st_sensor_data_ready_irq drdy_irq;
++ bool multi_read_bit;
++ unsigned int bootime;
++};
++
++/**
++ * struct st_sensor_data - ST sensor device status
++ * @dev: Pointer to instance of struct device (I2C or SPI).
++ * @trig: The trigger in use by the core driver.
++ * @sensor: Pointer to the current sensor struct in use.
++ * @current_fullscale: Maximum range of measure by the sensor.
++ * @enabled: Status of the sensor (false->off, true->on).
++ * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread.
++ * @buffer_data: Data used by buffer part.
++ * @odr: Output data rate of the sensor [Hz].
++ * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
++ * @tf: Transfer function structure used by I/O operations.
++ * @tb: Transfer buffers and mutex used by I/O operations.
++ */
++struct st_sensor_data {
++ struct device *dev;
++ struct iio_trigger *trig;
++ struct st_sensors *sensor;
++ struct st_sensor_fullscale_avl *current_fullscale;
++
++ bool enabled;
++ bool multiread_bit;
++
++ char *buffer_data;
++
++ unsigned int odr;
++
++ unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
++
++ const struct st_sensor_transfer_function *tf;
++ struct st_sensor_transfer_buffer tb;
++};
++
++#ifdef CONFIG_IIO_BUFFER
++irqreturn_t st_sensors_trigger_handler(int irq, void *p);
++
++int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf);
++#endif
++
++#ifdef CONFIG_IIO_TRIGGER
++int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
++ const struct iio_trigger_ops *trigger_ops);
++
++void st_sensors_deallocate_trigger(struct iio_dev *indio_dev);
++
++#else
++static inline int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
++ const struct iio_trigger_ops *trigger_ops)
++{
++ return 0;
++}
++static inline void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
++{
++ return;
++}
++#endif
++
++int st_sensors_init_sensor(struct iio_dev *indio_dev);
++
++int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
++ u8 reg_addr, u8 mask, u8 data);
++
++int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable);
++
++int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable);
++
++int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr);
++
++int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable);
++
++int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale);
++
++int st_sensors_read_axis_data(struct iio_dev *indio_dev,
++ u8 ch_addr, int *data);
++
++int st_sensors_read_info_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *ch, int *val);
++
++int st_sensors_check_device_support(struct iio_dev *indio_dev,
++ int num_sensors_list, const struct st_sensors *sensors);
++
++ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
++ struct device_attribute *attr, char *buf);
++
++ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size);
++
++ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
++ struct device_attribute *attr, char *buf);
++
++ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
++ struct device_attribute *attr, char *buf);
++
++#endif /* ST_SENSORS_H */
+diff --git a/include/linux/iio/common/st_sensors_i2c.h b/include/linux/iio/common/st_sensors_i2c.h
+new file mode 100644
+index 0000000..67d8453
+--- /dev/null
++++ b/include/linux/iio/common/st_sensors_i2c.h
+@@ -0,0 +1,20 @@
++/*
++ * STMicroelectronics sensors i2c library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#ifndef ST_SENSORS_I2C_H
++#define ST_SENSORS_I2C_H
++
++#include <linux/i2c.h>
++#include <linux/iio/common/st_sensors.h>
++
++void st_sensors_i2c_configure(struct iio_dev *indio_dev,
++ struct i2c_client *client, struct st_sensor_data *sdata);
++
++#endif /* ST_SENSORS_I2C_H */
+diff --git a/include/linux/iio/common/st_sensors_spi.h b/include/linux/iio/common/st_sensors_spi.h
+new file mode 100644
+index 0000000..d964a35
+--- /dev/null
++++ b/include/linux/iio/common/st_sensors_spi.h
+@@ -0,0 +1,20 @@
++/*
++ * STMicroelectronics sensors spi library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#ifndef ST_SENSORS_SPI_H
++#define ST_SENSORS_SPI_H
++
++#include <linux/spi/spi.h>
++#include <linux/iio/common/st_sensors.h>
++
++void st_sensors_spi_configure(struct iio_dev *indio_dev,
++ struct spi_device *spi, struct st_sensor_data *sdata);
++
++#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
+--- /dev/null
++++ b/include/linux/platform_data/lis331dlh_intel_qrk.h
+@@ -0,0 +1,36 @@
++/*
++ * 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.
++ *
++ * 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
++ *
++ */
++
++#ifndef __LINUX_PLATFORM_DATA_LIS331DLH_INTEL_QRK_H__
++#define __LINUX_PLATFORM_DATA_LIS331DLH_INTEL_QRK_H__
++
++/**
++ * struct lis331dlh_intel_qrk_platform_data - Platform data for the ST Micro
++ * accelerometer driver
++ * @irq1_pin: GPIO pin number for the threshold interrupt(INT1).
++ **/
++struct lis331dlh_intel_qrk_platform_data {
++ int irq1_pin;
++};
++
++#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
new file mode 100644
index 0000000..7c89b92
--- /dev/null
+++ b/recipes-kernel/linux/files/0019-Quark-SC-SPI-quark.patch
@@ -0,0 +1,2349 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Dan O'Donovan <danielx.o'donovan@intel.com>
+Date: Thu, 13 Feb 2014 16:41:02 +0000
+Subject: [PATCH 19/21] Quark SC SPI
+
+---
+ 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.c | 1290 +++++++++++++++++++++++++++-------------
+ include/linux/pxa2xx_ssp.h | 25 +
+ include/linux/spi/pxa2xx_spi.h | 15 +-
+ include/linux/spi/spi.h | 2 +
+ 8 files changed, 1078 insertions(+), 425 deletions(-)
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 2e188e1..71358a6 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -35,6 +35,14 @@ config SPI_DEBUG
+ Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
+ sysfs, and debugfs support in SPI controller and protocol drivers.
+
++config GEN3_SPI
++ bool "Intel Media SOC SPI support"
++ depends on SPI && ARCH_GEN3 && INTEL_QUARK_X1000_SOC
++ default y
++ help
++ This option enables Intel Media SOC SPI support.
++ For Quark this option depends on INTEL_QUARK_X1000_SOC.
++
+ #
+ # MASTER side ... talking to discrete SPI slave chips including microcontrollers
+ #
+@@ -74,7 +82,15 @@ config SPI_ATMEL
+ This selects a driver for the Atmel SPI Controller, present on
+ many AT32 (AVR32) and AT91 (ARM) chips.
+
+-config SPI_BFIN5XX
++config SPI_CE5XX_SPI_FLASH
++ tristate "CE5XX SPI FLASH"
++ depends on ARCH_GEN3 && HW_MUTEXES
++ default y
++ help
++ This selects a driver for CE5XX Serial Flash controler
++
++
++config SPI_BFIN
+ tristate "SPI controller driver for ADI Blackfin5xx"
+ depends on BLACKFIN
+ help
+@@ -302,12 +318,21 @@ config SPI_PXA2XX
+ depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
+ select PXA_SSP if ARCH_PXA
+ help
+- This enables using a PXA2xx or Sodaville SSP port as a SPI master
++ This enables using a PXA2xx or Intel CE4100/CE4200/CE5300 port as a SPI master
+ controller. The driver can be configured to use any SSP port and
+ additional documentation can be found a Documentation/spi/pxa2xx.
+
+ config SPI_PXA2XX_PCI
+- def_bool SPI_PXA2XX && X86_32 && PCI
++ tristate "Intel CE SPI PCI adapter"
++ depends on SPI_PXA2XX && X86_32 && PCI && GEN3_SPI
++ help
++ This driver supports the Intel CE SPI master controller and acts
++ as the PCI-SPI glue code for PXA's driver
++
++config SPI_CE5XX_SPI_SLAVE
++ tristate "CE5XX SPI SLAVE"
++ help
++ This selects a driver for CE5XX SPI Slave controler, it is emudulated into a spi device
+
+ config SPI_RSPI
+ tristate "Renesas RSPI controller"
+@@ -471,6 +496,14 @@ config SPI_DW_MMIO
+ depends on SPI_DESIGNWARE && HAVE_CLK
+
+ #
++# Bring out the LPC_SCH SPI block
++#
++
++config SPI_LPC_SCH
++ tristate "LPC SCH Legacy SPI controller"
++ depends on LPC_SCH
++
++#
+ # There are lots of SPI device types, with sensors and memory
+ # being probably the most widely used ones.
+ #
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 64e970b..b67de97 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
+ obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
+ obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
+ spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
++obj-$(CONFIG_SPI_LPC_SCH) += spi-lpc-sch.o
+ obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
+ obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
+ obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
+diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
+index c7cf0b7..0fa345c 100644
+--- a/drivers/spi/spi-gpio.c
++++ b/drivers/spi/spi-gpio.c
+@@ -265,9 +265,9 @@ static int spi_gpio_setup(struct spi_device *spi)
+ }
+ }
+ if (!status) {
+- status = spi_bitbang_setup(spi);
+ /* in case it was initialized from static board data */
+ spi_gpio->cs_gpios[spi->chip_select] = cs;
++ status = spi_bitbang_setup(spi);
+ }
+
+ if (status) {
+diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
+index cf95587..5250cd9 100644
+--- a/drivers/spi/spi-pxa2xx-pci.c
++++ b/drivers/spi/spi-pxa2xx-pci.c
+@@ -7,6 +7,47 @@
+ #include <linux/of_device.h>
+ #include <linux/module.h>
+ #include <linux/spi/pxa2xx_spi.h>
++#include <linux/irq.h>
++#include <linux/platform_data/quark.h>
++
++/* defined here to avoid including arch/x86/pci/intel_media_proc_gen3.c */
++#define CE3100_SOC_DEVICE_ID 0x2E50
++#define CE4100_SOC_DEVICE_ID 0x0708
++#define CE4200_SOC_DEVICE_ID 0x0709
++#define CE5300_SOC_DEVICE_ID 0x0C40
++#define CE2600_SOC_DEVICE_ID 0x0931
++
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
++#define CE4200_NUM_SPI_MASTER 1
++#else
++#define CE4200_NUM_SPI_MASTER 2
++#endif
++
++#define CE4X00_SPI_MAX_SPEED 1843200
++
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++#define CE4200_NUM_CHIPSELECT 2
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
++#define CE5X00_SPI_MAX_SPEED 3500000
++#else
++#define CE5X00_SPI_MAX_SPEED 50000000
++#endif
++#else
++#define CE4200_NUM_CHIPSELECT 4
++#define CE5X00_SPI_MAX_SPEED 5000000
++#endif
++
++#define SPI_CE_DEBUG
++
++static int interface;
++
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++static int enable_msi = 1;
++#else
++static int enable_msi;
++#endif
++module_param(enable_msi, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
+
+ struct ce4100_info {
+ struct ssp_device ssp;
+@@ -57,10 +98,11 @@ static int ce4100_spi_probe(struct pci_dev *dev,
+ int ret;
+ resource_size_t phys_beg;
+ resource_size_t phys_len;
+- struct ce4100_info *spi_info;
++ struct ce4100_info *spi_info = NULL;
+ struct platform_device *pdev;
+ struct pxa2xx_spi_master spi_pdata;
+ struct ssp_device *ssp;
++ unsigned int id;
+
+ ret = pci_enable_device(dev);
+ if (ret)
+@@ -77,42 +119,75 @@ static int ce4100_spi_probe(struct pci_dev *dev,
+ }
+
+ pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
++ if (!pdev) {
++ ret = -ENOMEM;
++ goto err_release_mem_region;
++ }
+ spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
+- if (!pdev || !spi_info ) {
++ if (!spi_info) {
+ ret = -ENOMEM;
+- goto err_nomem;
++ goto err_platform_device_put;
+ }
+ memset(&spi_pdata, 0, sizeof(spi_pdata));
+- spi_pdata.num_chipselect = dev->devfn;
++ spi_pdata.num_chipselect = CE4200_NUM_CHIPSELECT;
+
+ ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
+ if (ret)
+- goto err_nomem;
++ goto err_free_spi_info;
+
++ pdev->id = interface;
+ pdev->dev.parent = &dev->dev;
++#ifdef CONFIG_OF
+ pdev->dev.of_node = dev->dev.of_node;
++#endif
+ ssp = &spi_info->ssp;
++ ssp->pcidev = dev;
+ ssp->phys_base = pci_resource_start(dev, 0);
+ ssp->mmio_base = ioremap(phys_beg, phys_len);
+ if (!ssp->mmio_base) {
+ dev_err(&pdev->dev, "failed to ioremap() registers\n");
+ ret = -EIO;
+- goto err_nomem;
++ goto err_ioremap;
++ }
++ pci_set_master(dev);
++ if (enable_msi == 1) {
++ ret = pci_enable_msi(dev);
++ if (ret) {
++ dev_err(&dev->dev, "failed to allocate MSI entry\n");
++ goto err_dev_add;
++ }
+ }
++
+ ssp->irq = dev->irq;
+ ssp->port_id = pdev->id;
+- ssp->type = PXA25x_SSP;
+
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ id = CE5300_SOC_DEVICE_ID;
++#else
++ intelce_get_soc_info(&id, NULL);
++#endif
++ switch (id) {
++ case CE5300_SOC_DEVICE_ID:
++ ssp->type = CE5X00_SSP;
++ break;
++ case CE4200_SOC_DEVICE_ID:
++ default:
++ ssp->type = CE4100_SSP;
++ break;
++ }
+ mutex_lock(&ssp_lock);
+ list_add(&ssp->node, &ssp_list);
+ mutex_unlock(&ssp_lock);
+
+ pci_set_drvdata(dev, spi_info);
+
++ spi_info->spi_pdev = pdev;
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto err_dev_add;
+
++ interface++;
++
+ return ret;
+
+ err_dev_add:
+@@ -121,11 +196,16 @@ err_dev_add:
+ list_del(&ssp->node);
+ mutex_unlock(&ssp_lock);
+ iounmap(ssp->mmio_base);
++err_ioremap:
+
+-err_nomem:
+- release_mem_region(phys_beg, phys_len);
+- platform_device_put(pdev);
++err_free_spi_info:
+ kfree(spi_info);
++
++err_platform_device_put:
++ platform_device_put(pdev);
++
++err_release_mem_region:
++ release_mem_region(phys_beg, phys_len);
+ return ret;
+ }
+
+@@ -146,21 +226,50 @@ static void ce4100_spi_remove(struct pci_dev *dev)
+ list_del(&ssp->node);
+ mutex_unlock(&ssp_lock);
+
++ if (enable_msi == 1) {
++ if (pci_dev_msi_enabled(dev))
++ pci_disable_msi(dev);
++ }
++
+ pci_set_drvdata(dev, NULL);
+ pci_disable_device(dev);
+ kfree(spi_info);
+ }
+
++
++#ifdef CONFIG_PM
++static int ce4XXX_spi_suspend(struct pci_dev *dev, pm_message_t state)
++{
++ pci_save_state(dev);
++ pci_set_power_state(dev, pci_choose_state(dev, state));
++ return 0;
++}
++
++static int ce4XXX_spi_resume(struct pci_dev *dev)
++{
++ pci_set_power_state(dev, PCI_D0);
++ pci_restore_state(dev);
++
++ return 0;
++}
++#endif
++
+ static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0935) },
+ { },
+ };
++
+ MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
+
+ static struct pci_driver ce4100_spi_driver = {
+ .name = "ce4100_spi",
+ .id_table = ce4100_spi_devices,
+ .probe = ce4100_spi_probe,
++#ifdef CONFIG_PM
++ .suspend = ce4XXX_spi_suspend,
++ .resume = ce4XXX_spi_resume,
++#endif
+ .remove = ce4100_spi_remove,
+ };
+
+diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
+index 5c8c4f5..4860e85 100644
+--- a/drivers/spi/spi-pxa2xx.c
++++ b/drivers/spi/spi-pxa2xx.c
+@@ -26,14 +26,18 @@
+ #include <linux/spi/pxa2xx_spi.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/spi/spi.h>
+-#include <linux/workqueue.h>
+ #include <linux/delay.h>
++#include <linux/clk.h>
+ #include <linux/gpio.h>
+ #include <linux/slab.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/pm_runtime.h>
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++#include <asm/qrk.h>
++#endif
+
+-#include <asm/io.h>
+ #include <asm/irq.h>
+-#include <asm/delay.h>
+
+
+ MODULE_AUTHOR("Stephen Street");
+@@ -51,6 +55,9 @@ MODULE_ALIAS("platform:pxa2xx-spi");
+ #define MAX_DMA_LEN 8191
+ #define DMA_ALIGNMENT 8
+
++#define CE5X00_FIFO_DEPTH 32
++#define CE4X00_FIFO_DEPTH 4
++
+ /*
+ * for testing SSCR1 changes that require SSP restart, basically
+ * everything except the service and interrupt enables, the pxa270 developer
+@@ -59,35 +66,144 @@ MODULE_ALIAS("platform:pxa2xx-spi");
+ * service and interrupt enables
+ */
+ #define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
+- | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
+- | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
+- | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
+- | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
+- | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+-
+-#define DEFINE_SSP_REG(reg, off) \
+-static inline u32 read_##reg(void const __iomem *p) \
+-{ return __raw_readl(p + (off)); } \
+-\
+-static inline void write_##reg(u32 v, void __iomem *p) \
+-{ __raw_writel(v, p + (off)); }
+-
+-DEFINE_SSP_REG(SSCR0, 0x00)
+-DEFINE_SSP_REG(SSCR1, 0x04)
+-DEFINE_SSP_REG(SSSR, 0x08)
+-DEFINE_SSP_REG(SSITR, 0x0c)
+-DEFINE_SSP_REG(SSDR, 0x10)
+-DEFINE_SSP_REG(SSTO, 0x28)
+-DEFINE_SSP_REG(SSPSP, 0x2c)
+-
+-#define START_STATE ((void*)0)
+-#define RUNNING_STATE ((void*)1)
+-#define DONE_STATE ((void*)2)
+-#define ERROR_STATE ((void*)-1)
++ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
++ | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
++ | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
++ | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
++ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
++
++#define CE5X00_SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
++ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
++ | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
++ | SSCR1_IFS | CE5X00_SSCR1_STRF \
++ | CE5X00_SSCR1_EFWR \
++ | CE5X00_SSCR1_RFT | CE5X00_SSCR1_TFT \
++ | SSCR1_MWDS \
++ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
++
++
++#define DEFINE_SSP_REG(reg, off) \
++ static inline u32 read_##reg(void const __iomem *p) \
++ { return __raw_readl(p + (off)); } \
++ \
++ static inline void write_##reg(u32 v, void __iomem *p) \
++ { __raw_writel(v, p + (off)); }
++
++DEFINE_SSP_REG(sscr0, 0x00)
++DEFINE_SSP_REG(sscr1, 0x04)
++DEFINE_SSP_REG(sssr, 0x08)
++DEFINE_SSP_REG(ssitr, 0x0c)
++DEFINE_SSP_REG(ssdr, 0x10)
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++DEFINE_SSP_REG(dds_rate, 0x28) /* SSTO unused for qrk */
++#endif
++DEFINE_SSP_REG(ssto, 0x28)
++DEFINE_SSP_REG(sspsp, 0x2c)
++
++#define START_STATE ((void *)0)
++#define RUNNING_STATE ((void *)1)
++#define DONE_STATE ((void *)2)
++#define ERROR_STATE ((void *)-1)
+
+ #define QUEUE_RUNNING 0
+ #define QUEUE_STOPPED 1
+
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++#define DDS_MAX 0x800000
++#define DDS_666666 0x666666
++#define DDS_400000 0x400000
++#define DDS_200000 0x200000
++#define DDS_100000 0x100000
++#define DDS_80000 0x80000
++#define DDS_40000 0x40000
++#define DDS_20000 0x20000
++#define DDS_10000 0x10000
++#define DDS_8000 0x8000
++
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU)
++/* these values are different on emulations where system clock is 14mhz */
++#define FSYS 14 /* mhz */
++#define BITRATE_50MHZ 3500000
++#define BITRATE_40MHZ 2800000
++#define BITRATE_25MHZ 1750000
++#define BITRATE_20MHZ 1400000
++#define BITRATE_16667KHZ 1167000
++#define BITRATE_13333KHZ 933000
++#define BITRATE_12500KHZ 875000
++#define BITRATE_10MHZ 700000
++#define BITRATE_8MHZ 560000
++#define BITRATE_6250KHZ 438000
++#define BITRATE_5MHZ 350000
++#define BITRATE_4MHZ 280000
++#define BITRATE_3125KHZ 219000
++#define BITRATE_2500KHZ 175000
++#define BITRATE_2MHZ 140000
++#define BITRATE_1563KHZ 109000
++#define BITRATE_1250KHZ 88000
++#define BITRATE_1MHZ 70000
++#define BITRATE_800KHZ 56000
++#define BITRATE_781KHZ 54688
++#define BITRATE_625KHZ 43750
++#define BITRATE_500KHZ 35000
++#define BITRATE_400KHZ 28000
++#define BITRATE_390KHZ 27344
++#define BITRATE_250KHZ 17500
++#define BITRATE_200KHZ 14000
++#define BITRATE_195KHZ 13672
++#define BITRATE_125KHZ 8750
++#define BITRATE_100KHZ 7000
++#define BITRATE_50KHZ 3500
++#define BITRATE_25KHZ 1750
++#define BITRATE_10KHZ 701
++#define BITRATE_5KHZ 353
++#define BITRATE_1KHZ 70
++#define BITRATE_MAX BITRATE_50MHZ
++#define BITRATE_MIN BITRATE_1KHZ
++
++#else
++
++#define BITRATE_50MHZ 50000000
++#define BITRATE_40MHZ 40000000
++#define BITRATE_25MHZ 25000000
++#define BITRATE_20MHZ 20000000
++#define BITRATE_16667KHZ 16667000
++#define BITRATE_13333KHZ 13333000
++#define BITRATE_12500KHZ 12500000
++#define BITRATE_10MHZ 10000000
++#define BITRATE_8MHZ 8000000
++#define BITRATE_6250KHZ 6250000
++#define BITRATE_5MHZ 5000000
++#define BITRATE_4MHZ 4000000
++#define BITRATE_3125KHZ 3125000
++#define BITRATE_2500KHZ 2500000
++#define BITRATE_2MHZ 2000000
++#define BITRATE_1563KHZ 1563000
++#define BITRATE_1250KHZ 1250000
++#define BITRATE_1MHZ 1000000
++#define BITRATE_800KHZ 800000
++#define BITRATE_781KHZ 781250
++#define BITRATE_625KHZ 625000
++#define BITRATE_500KHZ 500000
++#define BITRATE_400KHZ 400000
++#define BITRATE_390KHZ 390625
++#define BITRATE_250KHZ 250000
++#define BITRATE_200KHZ 200000
++#define BITRATE_195KHZ 195313
++#define BITRATE_125KHZ 125000
++#define BITRATE_100KHZ 100000
++#define BITRATE_50KHZ 50000
++#define BITRATE_25KHZ 25000
++#define BITRATE_10KHZ 10016
++#define BITRATE_5KHZ 5040
++#define BITRATE_1KHZ 1000
++#define BITRATE_MIN BITRATE_1KHZ
++#define BITRATE_MAX BITRATE_50MHZ
++#define FSYS 200 /* mhz */
++
++#endif /* #if defined(CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU) */
++
++#endif /* CONFIG_INTEL_QUARK_X1000_SOC */
++
+ struct driver_data {
+ /* Driver model hookup */
+ struct platform_device *pdev;
+@@ -117,20 +233,12 @@ struct driver_data {
+ u32 clear_sr;
+ u32 mask_sr;
+
+- /* Driver message queue */
+- struct workqueue_struct *workqueue;
+- struct work_struct pump_messages;
+- spinlock_t lock;
+- struct list_head queue;
+- int busy;
+- int run;
+-
+- /* Message Transfer pump */
++ /* Message per-transfer pump */
+ struct tasklet_struct pump_transfers;
+
+ /* Current message transfer state info */
+- struct spi_message* cur_msg;
+- struct spi_transfer* cur_transfer;
++ struct spi_message *cur_msg;
++ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+ size_t len;
+ void *tx;
+@@ -153,6 +261,9 @@ struct driver_data {
+ struct chip_data {
+ u32 cr0;
+ u32 cr1;
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ u32 dds_rate;
++#endif
+ u32 psp;
+ u32 timeout;
+ u8 n_bytes;
+@@ -173,14 +284,14 @@ struct chip_data {
+ void (*cs_control)(u32 command);
+ };
+
+-static void pump_messages(struct work_struct *work);
+-
+ static void cs_assert(struct driver_data *drv_data)
+ {
+ struct chip_data *chip = drv_data->cur_chip;
+
+- if (drv_data->ssp_type == CE4100_SSP) {
+- write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
++ if (drv_data->ssp_type == CE4100_SSP ||
++ (drv_data->ssp_type == CE5X00_SSP &&
++ (!gpio_is_valid(chip->gpio_cs)))) {
++ write_sssr(drv_data->cur_chip->frm, drv_data->ioaddr);
+ return;
+ }
+
+@@ -197,9 +308,11 @@ static void cs_deassert(struct driver_data *drv_data)
+ {
+ struct chip_data *chip = drv_data->cur_chip;
+
+- if (drv_data->ssp_type == CE4100_SSP)
++ if (drv_data->ssp_type == CE4100_SSP ||
++ (drv_data->ssp_type == CE5X00_SSP
++ && (!gpio_is_valid(chip->gpio_cs)))) {
+ return;
+-
++ }
+ if (chip->cs_control) {
+ chip->cs_control(PXA2XX_CS_DEASSERT);
+ return;
+@@ -209,14 +322,15 @@ static void cs_deassert(struct driver_data *drv_data)
+ gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
+ }
+
+-static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
++static void write_sssr_cs(struct driver_data *drv_data, u32 val)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- if (drv_data->ssp_type == CE4100_SSP)
+- val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
++ if (drv_data->ssp_type == CE4100_SSP
++ || drv_data->ssp_type == CE5X00_SSP)
++ val |= read_sssr(reg) & SSSR_ALT_FRM_MASK;
+
+- write_SSSR(val, reg);
++ write_sssr(val, reg);
+ }
+
+ static int pxa25x_ssp_comp(struct driver_data *drv_data)
+@@ -225,6 +339,10 @@ static int pxa25x_ssp_comp(struct driver_data *drv_data)
+ return 1;
+ if (drv_data->ssp_type == CE4100_SSP)
+ return 1;
++#ifdef CONFIG_GEN3_SPI
++ if (drv_data->ssp_type == CE5X00_SSP)
++ return 2;
++#endif
+ return 0;
+ }
+
+@@ -235,25 +353,46 @@ static int flush(struct driver_data *drv_data)
+ void __iomem *reg = drv_data->ioaddr;
+
+ do {
+- while (read_SSSR(reg) & SSSR_RNE) {
+- read_SSDR(reg);
+- }
+- } while ((read_SSSR(reg) & SSSR_BSY) && --limit);
+- write_SSSR_CS(drv_data, SSSR_ROR);
++ while (read_sssr(reg) & SSSR_RNE)
++ read_ssdr(reg);
++ } while ((read_sssr(reg) & SSSR_BSY) && --limit);
++ write_sssr_cs(drv_data, SSSR_ROR);
+
+ return limit;
+ }
+
++#ifdef CONFIG_GEN3_SPI
++static void wait_till_not_busy(struct driver_data *drv_data)
++{
++ /*
++ * Most cases, the BSY bit will be cleared in very short time.
++ * But if the controller is set to the slowest speed, the BSY
++ * bit waitting time will increase a lot.
++ * Here, we set the wait time to 100ms is to deal with such corner case,
++ * but in real world, there is almost no one will use the slowest
++ * speed to transfer data, which means there is no need to add more
++ * complex code to to deal with the slowest speed case.
++ */
++ unsigned long end = jiffies + 1 + usecs_to_jiffies(100000);
++ void __iomem *reg = drv_data->ioaddr;
++ while (time_before(jiffies, end)) {
++ if (!(read_sssr(reg) & SSSR_BSY))
++ return;
++ }
++ pr_err("SPI MASTER keeps busy for 100ms after a read/write!\n");
++}
++#endif
++
+ static int null_writer(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+ u8 n_bytes = drv_data->n_bytes;
+
+- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+- || (drv_data->tx == drv_data->tx_end))
++ if ((!(read_sssr(reg) & SSSR_TNF))
++ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+- write_SSDR(0, reg);
++ write_ssdr(0, reg);
+ drv_data->tx += n_bytes;
+
+ return 1;
+@@ -264,9 +403,9 @@ static int null_reader(struct driver_data *drv_data)
+ void __iomem *reg = drv_data->ioaddr;
+ u8 n_bytes = drv_data->n_bytes;
+
+- while ((read_SSSR(reg) & SSSR_RNE)
++ while ((read_sssr(reg) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+- read_SSDR(reg);
++ read_ssdr(reg);
+ drv_data->rx += n_bytes;
+ }
+
+@@ -277,11 +416,11 @@ static int u8_writer(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+- || (drv_data->tx == drv_data->tx_end))
++ if ((!(read_sssr(reg) & SSSR_TNF))
++ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+- write_SSDR(*(u8 *)(drv_data->tx), reg);
++ write_ssdr(*(u8 *)(drv_data->tx), reg);
+ ++drv_data->tx;
+
+ return 1;
+@@ -291,9 +430,9 @@ static int u8_reader(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- while ((read_SSSR(reg) & SSSR_RNE)
+- && (drv_data->rx < drv_data->rx_end)) {
+- *(u8 *)(drv_data->rx) = read_SSDR(reg);
++ while ((read_sssr(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ *(u8 *)(drv_data->rx) = read_ssdr(reg);
+ ++drv_data->rx;
+ }
+
+@@ -304,11 +443,11 @@ static int u16_writer(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+- || (drv_data->tx == drv_data->tx_end))
++ if ((!(read_sssr(reg) & SSSR_TNF))
++ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+- write_SSDR(*(u16 *)(drv_data->tx), reg);
++ write_ssdr(*(u16 *)(drv_data->tx), reg);
+ drv_data->tx += 2;
+
+ return 1;
+@@ -318,9 +457,9 @@ static int u16_reader(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- while ((read_SSSR(reg) & SSSR_RNE)
+- && (drv_data->rx < drv_data->rx_end)) {
+- *(u16 *)(drv_data->rx) = read_SSDR(reg);
++ while ((read_sssr(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ *(u16 *)(drv_data->rx) = read_ssdr(reg);
+ drv_data->rx += 2;
+ }
+
+@@ -331,11 +470,11 @@ static int u32_writer(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+- || (drv_data->tx == drv_data->tx_end))
++ if ((!(read_sssr(reg) & SSSR_TNF))
++ || (drv_data->tx == drv_data->tx_end))
+ return 0;
+
+- write_SSDR(*(u32 *)(drv_data->tx), reg);
++ write_ssdr(*(u32 *)(drv_data->tx), reg);
+ drv_data->tx += 4;
+
+ return 1;
+@@ -345,9 +484,9 @@ static int u32_reader(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- while ((read_SSSR(reg) & SSSR_RNE)
+- && (drv_data->rx < drv_data->rx_end)) {
+- *(u32 *)(drv_data->rx) = read_SSDR(reg);
++ while ((read_sssr(reg) & SSSR_RNE)
++ && (drv_data->rx < drv_data->rx_end)) {
++ *(u32 *)(drv_data->rx) = read_ssdr(reg);
+ drv_data->rx += 4;
+ }
+
+@@ -443,20 +582,11 @@ static void unmap_dma_buffers(struct driver_data *drv_data)
+ /* caller already set message->status; dma and pio irqs are blocked */
+ static void giveback(struct driver_data *drv_data)
+ {
+- struct spi_transfer* last_transfer;
+- unsigned long flags;
+- struct spi_message *msg;
++ struct spi_transfer *last_transfer;
+
+- spin_lock_irqsave(&drv_data->lock, flags);
+- msg = drv_data->cur_msg;
+- drv_data->cur_msg = NULL;
+- drv_data->cur_transfer = NULL;
+- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+-
+- last_transfer = list_entry(msg->transfers.prev,
+- struct spi_transfer,
+- transfer_list);
++ last_transfer = list_entry(drv_data->cur_msg->transfers.prev,
++ struct spi_transfer,
++ transfer_list);
+
+ /* Delay if requested before any change in chip select */
+ if (last_transfer->delay_usecs)
+@@ -475,41 +605,33 @@ static void giveback(struct driver_data *drv_data)
+ * time with the following tests unless this was hinted.
+ *
+ * We cannot postpone this until pump_messages, because
+- * after calling msg->complete (below) the driver that
+- * sent the current message could be unloaded, which
+- * could invalidate the cs_control() callback...
++ * after calling spi_finalize_current_message (below) the
++ * driver that sent the current message could be unloaded,
++ * which could invalidate the cs_control() callback...
+ */
+-
+ /* get a pointer to the next message, if any */
+- spin_lock_irqsave(&drv_data->lock, flags);
+- if (list_empty(&drv_data->queue))
+- next_msg = NULL;
+- else
+- next_msg = list_entry(drv_data->queue.next,
+- struct spi_message, queue);
+- spin_unlock_irqrestore(&drv_data->lock, flags);
++ next_msg = spi_get_next_queued_message(drv_data->master);
+
+ /* see if the next and current messages point
+ * to the same chip
+ */
+- if (next_msg && next_msg->spi != msg->spi)
++ if (next_msg && next_msg->spi != drv_data->cur_msg->spi)
+ next_msg = NULL;
+- if (!next_msg || msg->state == ERROR_STATE)
++ if (!next_msg || drv_data->cur_msg->state == ERROR_STATE)
+ cs_deassert(drv_data);
+ }
+
+- msg->state = NULL;
+- if (msg->complete)
+- msg->complete(msg->context);
+-
++ drv_data->cur_msg = NULL;
++ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
++ spi_finalize_current_message(drv_data->master);
+ }
+
+ static int wait_ssp_rx_stall(void const __iomem *ioaddr)
+ {
+ unsigned long limit = loops_per_jiffy << 1;
+
+- while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
++ while ((read_sssr(ioaddr) & SSSR_BSY) && --limit)
+ cpu_relax();
+
+ return limit;
+@@ -532,12 +654,12 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
+ /* Stop and reset */
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+- write_SSSR_CS(drv_data, drv_data->clear_sr);
+- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
++ write_sssr_cs(drv_data, drv_data->clear_sr);
++ write_sscr1(read_sscr1(reg) & ~drv_data->dma_cr1, reg);
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(0, reg);
++ write_ssto(0, reg);
+ flush(drv_data);
+- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
++ write_sscr0(read_sscr0(reg) & ~SSCR0_SSE, reg);
+
+ unmap_dma_buffers(drv_data);
+
+@@ -553,8 +675,8 @@ static void dma_transfer_complete(struct driver_data *drv_data)
+ struct spi_message *msg = drv_data->cur_msg;
+
+ /* Clear and disable interrupts on SSP and DMA channels*/
+- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+- write_SSSR_CS(drv_data, drv_data->clear_sr);
++ write_sscr1(read_sscr1(reg) & ~drv_data->dma_cr1, reg);
++ write_sssr_cs(drv_data, drv_data->clear_sr);
+ DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
+ DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
+
+@@ -630,7 +752,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
+ u32 irq_status;
+ void __iomem *reg = drv_data->ioaddr;
+
+- irq_status = read_SSSR(reg) & drv_data->mask_sr;
++ irq_status = read_sssr(reg) & drv_data->mask_sr;
+ if (irq_status & SSSR_ROR) {
+ dma_error_stop(drv_data, "dma_transfer: fifo overrun");
+ return IRQ_HANDLED;
+@@ -639,7 +761,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
+ /* Check for false positive timeout */
+ if ((irq_status & SSSR_TINT)
+ && (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
+- write_SSSR(SSSR_TINT, reg);
++ write_sssr(SSSR_TINT, reg);
+ return IRQ_HANDLED;
+ }
+
+@@ -648,7 +770,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
+ /* Clear and disable timeout interrupt, do the rest in
+ * dma_transfer_complete */
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(0, reg);
++ write_ssto(0, reg);
+
+ /* finish this transfer, start the next */
+ dma_transfer_complete(drv_data);
+@@ -666,23 +788,26 @@ static void reset_sccr1(struct driver_data *drv_data)
+ struct chip_data *chip = drv_data->cur_chip;
+ u32 sccr1_reg;
+
+- sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
+- sccr1_reg &= ~SSCR1_RFT;
++ sccr1_reg = read_sscr1(reg) & ~drv_data->int_cr1;
++ if (drv_data->ssp_type == CE5X00_SSP)
++ sccr1_reg &= ~CE5X00_SSCR1_RFT;
++ else
++ sccr1_reg &= ~SSCR1_RFT;
+ sccr1_reg |= chip->threshold;
+- write_SSCR1(sccr1_reg, reg);
++ write_sscr1(sccr1_reg, reg);
+ }
+
+-static void int_error_stop(struct driver_data *drv_data, const char* msg)
++static void int_error_stop(struct driver_data *drv_data, const char *msg)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+ /* Stop and reset SSP */
+- write_SSSR_CS(drv_data, drv_data->clear_sr);
++ write_sssr_cs(drv_data, drv_data->clear_sr);
+ reset_sccr1(drv_data);
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(0, reg);
++ write_ssto(0, reg);
+ flush(drv_data);
+- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
++ write_sscr0(read_sscr0(reg) & ~SSCR0_SSE, reg);
+
+ dev_err(&drv_data->pdev->dev, "%s\n", msg);
+
+@@ -695,10 +820,10 @@ static void int_transfer_complete(struct driver_data *drv_data)
+ void __iomem *reg = drv_data->ioaddr;
+
+ /* Stop SSP */
+- write_SSSR_CS(drv_data, drv_data->clear_sr);
++ write_sssr_cs(drv_data, drv_data->clear_sr);
+ reset_sccr1(drv_data);
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(0, reg);
++ write_ssto(0, reg);
+
+ /* Update total byte transferred return count actual bytes read */
+ drv_data->cur_msg->actual_length += drv_data->len -
+@@ -715,14 +840,16 @@ static void int_transfer_complete(struct driver_data *drv_data)
+ tasklet_schedule(&drv_data->pump_transfers);
+ }
+
++#ifndef CONFIG_GEN3_SPI
++
+ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+ {
+ void __iomem *reg = drv_data->ioaddr;
+
+- u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
++ u32 irq_mask = (read_sscr1(reg) & SSCR1_TIE) ?
+ drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
+
+- u32 irq_status = read_SSSR(reg) & irq_mask;
++ u32 irq_status = read_sssr(reg) & irq_mask;
+
+ if (irq_status & SSSR_ROR) {
+ int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
+@@ -730,7 +857,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+ }
+
+ if (irq_status & SSSR_TINT) {
+- write_SSSR(SSSR_TINT, reg);
++ write_sssr_cs(drv_data, SSSR_TINT);
+ if (drv_data->read(drv_data)) {
+ int_transfer_complete(drv_data);
+ return IRQ_HANDLED;
+@@ -751,10 +878,12 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+ }
+
+ if (drv_data->tx == drv_data->tx_end) {
+- u32 bytes_left;
++#ifndef CONFIG_GEN3_SPI
++ u32 bytes_left = 0;
++#endif
+ u32 sccr1_reg;
+
+- sccr1_reg = read_SSCR1(reg);
++ sccr1_reg = read_sscr1(reg);
+ sccr1_reg &= ~SSCR1_TIE;
+
+ /*
+@@ -762,13 +891,13 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+ * remaining RX bytes.
+ */
+ if (pxa25x_ssp_comp(drv_data)) {
+-
++#ifndef CONFIG_GEN3_SPI
+ sccr1_reg &= ~SSCR1_RFT;
+
+ bytes_left = drv_data->rx_end - drv_data->rx;
+ switch (drv_data->n_bytes) {
+ case 4:
+- bytes_left >>= 1;
++ bytes_left >>= 2;
+ case 2:
+ bytes_left >>= 1;
+ }
+@@ -777,23 +906,198 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
+ bytes_left = RX_THRESH_DFLT;
+
+ sccr1_reg |= SSCR1_RxTresh(bytes_left);
++#endif
++ }
++ write_sscr1(sccr1_reg, reg);
++#ifdef CONFIG_GEN3_SPI
++ if (!wait_ssp_rx_stall(reg)) {
++ int_error_stop(drv_data,
++ "interrupt_transfer: rx stall failed");
++ return IRQ_HANDLED;
++ }
++
++ if (!drv_data->read(drv_data)) {
++ int_error_stop(drv_data,
++ "interrupt_transfer: "
++ "trailing byte read failed");
++ return IRQ_HANDLED;
++ }
++
++ int_transfer_complete(drv_data);
++#endif
++
++ }
++
++ /* We did something */
++ return IRQ_HANDLED;
++}
++#else
++#ifdef WANT_TO_USE_THIS
++static int is_txfifo_empty(struct driver_data *drv_data, u32 tfl_mask)
++{
++ void __iomem *reg = drv_data->ioaddr;
++ u32 sssr = read_sssr(reg);
++ u32 tx_fifo_entry = 0;
++ tx_fifo_entry = (sssr & tfl_mask)>>8;
++ if ((sssr & SSSR_TNF) && (!tx_fifo_entry))
++ return 1;
++ return 0;
++}
++#endif
++
++static void pxa2xx_update_tx_threshold(struct driver_data *drv_data,
++ u32 threshold)
++{
++ void __iomem *reg = drv_data->ioaddr;
++ u32 sscr1_reg = 0;
++ sscr1_reg = read_sscr1(reg);
++ sscr1_reg |= SSCR1_TIE;
++ if (drv_data->ssp_type == CE5X00_SSP) {
++ sscr1_reg &= ~CE5X00_SSCR1_TFT;
++ sscr1_reg |= CE5X00_SSCR1_TxTresh(threshold);
++ } else {
++ sscr1_reg &= ~SSCR1_TFT;
++ sscr1_reg |= SSCR1_TxTresh(threshold);
++ }
++
++ write_sscr1(sscr1_reg, reg);
++}
++
++static void pxa2xx_mask_intr(void __iomem *reg, u32 intr)
++{
++ u32 mask;
++ mask = read_sscr1(reg) & ~intr;
++ write_sscr1(mask, reg);
++}
++
++static void pxa2xx_unmask_intr(void __iomem *reg, u32 intr)
++{
++ u32 mask;
++ mask = read_sscr1(reg) | intr;
++ write_sscr1(mask, reg);
++}
++
++static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
++{
++ void __iomem *reg = drv_data->ioaddr;
++
++ u32 tx_count;
++ u32 irq_mask = (read_sscr1(reg) & SSCR1_TIE) ?
++ drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
++
++ int left;
++
++ u32 tmp_sssr = read_sssr(reg);
++ u32 irq_status = tmp_sssr & irq_mask;
++ /*
++ * Transmit FIFO Level Depth/MASK/Default value
++ */
++ u32 fifo_depth, sssr_tfl_mask, sscr1_tft_mask, tfl_default;
++
++ /*
++ * Check whether the irq is valid spi interrupt
++ */
++ if (!(tmp_sssr & (SSSR_TFS | SSSR_RFS | SSSR_ROR)))
++ return IRQ_NONE;
++
++ switch (drv_data->ssp_type) {
++ case CE4100_SSP:
++ fifo_depth = CE4X00_FIFO_DEPTH;
++ sssr_tfl_mask = SSSR_TFL_MASK;
++ sscr1_tft_mask = SSCR1_TFT;
++ tfl_default = TX_THRESH_DFLT;
++ break;
++ case CE5X00_SSP:
++ fifo_depth = CE5X00_FIFO_DEPTH;
++ sssr_tfl_mask = CE5X00_SSSR_TFL_MASK;
++ sscr1_tft_mask = CE5X00_SSCR1_TFT;
++ tfl_default = TX_THRESH_CE5X00_DFLT;
++ break;
++ default:
++ int_error_stop(drv_data, "Unsupported spi contoller type");
++ return IRQ_HANDLED;
++ }
++
++
++ if (irq_status & SSSR_ROR) {
++ int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
++ return IRQ_HANDLED;
++ }
++
++
++ if (irq_status & SSSR_TINT) {
++ write_sssr_cs(drv_data, SSSR_TINT);
++ if (drv_data->read(drv_data)) {
++ int_transfer_complete(drv_data);
++ return IRQ_HANDLED;
+ }
+- write_SSCR1(sccr1_reg, reg);
+ }
+
++
++ if (irq_status & SSSR_TFS) {
++
++ /*
++ * Mask the Transmit interrupt
++ */
++ pxa2xx_mask_intr(reg, SSCR1_TIE);
++
++ left = (drv_data->tx_end - drv_data->tx) / drv_data->n_bytes;
++
++ tmp_sssr = read_sssr(reg);
++ tmp_sssr = (tmp_sssr & sssr_tfl_mask)>>8;
++ /*
++ * Choose the correct tx_count to fill the Tx fifo and
++ * avoid the Rx Fifo overrun
++ */
++ tx_count = (fifo_depth - 1) - tmp_sssr;
++
++ if (left <= tx_count) {
++ if (left > 0) {
++ drv_data->read(drv_data);
++ pxa2xx_update_tx_threshold(drv_data, 1);
++ while ((left) > 0) {
++ left--;
++ drv_data->write(drv_data);
++ }
++ pxa2xx_unmask_intr(reg, SSCR1_TIE);
++ return IRQ_HANDLED;
++ } else {
++ /*
++ * Tx transfer is done now,
++ * Read data when controller is not busy.
++ */
++ wait_till_not_busy(drv_data);
++ drv_data->read(drv_data);
++ pxa2xx_unmask_intr(reg, SSCR1_TIE);
++ int_transfer_complete(drv_data);
++ return IRQ_HANDLED;
++ }
++ } else {
++ left = (left > tx_count) ? tx_count : left;
++ drv_data->read(drv_data);
++ while ((left) > 0) {
++ left--;
++ drv_data->write(drv_data);
++ }
++ pxa2xx_unmask_intr(reg, SSCR1_TIE);
++ return IRQ_HANDLED;
++ }
++ }
+ /* We did something */
+ return IRQ_HANDLED;
+ }
++#endif
+
+ static irqreturn_t ssp_int(int irq, void *dev_id)
+ {
+ struct driver_data *drv_data = dev_id;
+ void __iomem *reg = drv_data->ioaddr;
+- u32 sccr1_reg = read_SSCR1(reg);
++ u32 sccr1_reg = read_sscr1(reg);
+ u32 mask = drv_data->mask_sr;
+ u32 status;
++ irqreturn_t ret;
+
+- status = read_SSSR(reg);
++ status = read_sssr(reg);
+
+ /* Ignore possible writes if we don't need to write */
+ if (!(sccr1_reg & SSCR1_TIE))
+@@ -802,22 +1106,27 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
+ if (!(status & mask))
+ return IRQ_NONE;
+
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ mask_pvm(drv_data->ssp->pcidev);
++#endif
+ if (!drv_data->cur_msg) {
+
+- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
++ write_sscr0(read_sscr0(reg) & ~SSCR0_SSE, reg);
++ write_sscr1(read_sscr1(reg) & ~drv_data->int_cr1, reg);
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(0, reg);
+- write_SSSR_CS(drv_data, drv_data->clear_sr);
+-
+- dev_err(&drv_data->pdev->dev, "bad message state "
+- "in interrupt handler\n");
++ write_ssto(0, reg);
++ write_sssr_cs(drv_data, drv_data->clear_sr);
+
++ dev_err(&drv_data->pdev->dev,
++ "bad message state in interrupt handler\n");
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+-
+- return drv_data->transfer_handler(drv_data);
++ ret = drv_data->transfer_handler(drv_data);
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ unmask_pvm(drv_data->ssp->pcidev);
++#endif
++ return ret;
+ }
+
+ static int set_dma_burst_and_threshold(struct chip_data *chip,
+@@ -916,16 +1225,192 @@ static int set_dma_burst_and_threshold(struct chip_data *chip,
+
+ return retval;
+ }
++#ifdef CONFIG_GEN3_SPI
++/* this returns the value of DDS_FREQ not Input_Clock
++ DDS_FREQ = Input_Clock ( DDS_CLK_RATEdec / 2^24) */
++static unsigned long spi_clk_get_rate(int ssp_type)
++{
++ switch (ssp_type) {
++ case CE5X00_SSP:
++ /* CE5X00 clk is 10MHZ */
++ return 10000000;
++ case CE4100_SSP:
++ /* CE4X00 clk is 3.684MHZ */
++ default:
++ return 3686400;
++ }
+
++ return 3686400;
++}
++#endif
++
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++/* see Quark SPI data sheet for implementation rationale */
++u32 qrk_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div)
++{
++ if (rate <= BITRATE_MAX && rate >= BITRATE_MIN) {
++ if (rate >= BITRATE_50MHZ) {
++ *dds = DDS_MAX;
++ *clk_div = 0;
++ return BITRATE_50MHZ;
++ } else if (rate >= BITRATE_40MHZ) {
++ *dds = DDS_666666;
++ *clk_div = 0;
++ return BITRATE_40MHZ;
++ } else if (rate >= BITRATE_25MHZ) {
++ *dds = DDS_400000;
++ *clk_div = 0;
++ return BITRATE_25MHZ;
++ } else if (rate >= BITRATE_20MHZ) {
++ *dds = DDS_666666;
++ *clk_div = 1;
++ return BITRATE_20MHZ;
++ } else if (rate >= BITRATE_16667KHZ) {
++ *dds = DDS_MAX;
++ *clk_div = 2;
++ return BITRATE_16667KHZ;
++ } else if (rate >= BITRATE_13333KHZ) {
++ *dds = DDS_666666;
++ *clk_div = 2;
++ return BITRATE_13333KHZ;
++ } else if (rate >= BITRATE_12500KHZ) {
++ *dds = DDS_200000;
++ *clk_div = 0;
++ return BITRATE_12500KHZ;
++ } else if (rate >= BITRATE_10MHZ) {
++ *dds = DDS_MAX;
++ *clk_div = 4;
++ return BITRATE_10MHZ;
++ } else if (rate >= BITRATE_8MHZ) {
++ *dds = DDS_666666;
++ *clk_div = 4;
++ return BITRATE_8MHZ;
++ } else if (rate >= BITRATE_6250KHZ) {
++ *dds = DDS_400000;
++ *clk_div = 3;
++ return BITRATE_6250KHZ;
++ } else if (rate >= BITRATE_5MHZ) {
++ *dds = DDS_400000;
++ *clk_div = 4;
++ return BITRATE_5MHZ;
++ } else if (rate >= BITRATE_4MHZ) {
++ *dds = DDS_666666;
++ *clk_div = 9;
++ return BITRATE_4MHZ;
++ } else if (rate >= BITRATE_3125KHZ) {
++ *dds = DDS_80000;
++ *clk_div = 0;
++ return BITRATE_3125KHZ;
++ } else if (rate >= BITRATE_2500KHZ) {
++ *dds = DDS_400000;
++ *clk_div = 9;
++ return BITRATE_2500KHZ;
++ } else if (rate >= BITRATE_2MHZ) {
++ *dds = DDS_666666;
++ *clk_div = 19;
++ return BITRATE_2MHZ;
++ } else if (rate >= BITRATE_1563KHZ) {
++ *dds = DDS_40000;
++ *clk_div = 0;
++ return BITRATE_1563KHZ;
++ } else if (rate >= BITRATE_1250KHZ) {
++ *dds = DDS_200000;
++ *clk_div = 9;
++ return BITRATE_1250KHZ;
++ } else if (rate >= BITRATE_1MHZ) {
++ *dds = DDS_400000;
++ *clk_div = 24;
++ return BITRATE_1MHZ;
++ } else if (rate >= BITRATE_800KHZ) {
++ *dds = DDS_666666;
++ *clk_div = 49;
++ return BITRATE_800KHZ;
++ } else if (rate >= BITRATE_781KHZ) {
++ *dds = DDS_20000;
++ *clk_div = 0;
++ return BITRATE_781KHZ;
++ } else if (rate >= BITRATE_625KHZ) {
++ *dds = DDS_200000;
++ *clk_div = 19;
++ return BITRATE_625KHZ;
++ } else if (rate >= BITRATE_500KHZ) {
++ *dds = DDS_400000;
++ *clk_div = 49;
++ return BITRATE_500KHZ;
++ } else if (rate >= BITRATE_400KHZ) {
++ *dds = DDS_666666;
++ *clk_div = 99;
++ return BITRATE_400KHZ;
++ } else if (rate >= BITRATE_390KHZ) {
++ *dds = DDS_10000;
++ *clk_div = 0;
++ return BITRATE_390KHZ;
++ } else if (rate >= BITRATE_250KHZ) {
++ *dds = DDS_400000;
++ *clk_div = 99;
++ return BITRATE_250KHZ;
++ } else if (rate >= BITRATE_200KHZ) {
++ *dds = DDS_666666;
++ *clk_div = 199;
++ return BITRATE_200KHZ;
++ } else if (rate >= BITRATE_195KHZ) {
++ *dds = DDS_8000;
++ *clk_div = 0;
++ return BITRATE_195KHZ;
++ } else if (rate >= BITRATE_125KHZ) {
++ *dds = DDS_100000;
++ *clk_div = 49;
++ return BITRATE_125KHZ;
++ } else if (rate >= BITRATE_100KHZ) {
++ *dds = DDS_200000;
++ *clk_div = 124;
++ return BITRATE_100KHZ;
++ } else if (rate >= BITRATE_50KHZ) {
++ *dds = DDS_100000;
++ *clk_div = 124;
++ return BITRATE_50KHZ;
++ } else if (rate >= BITRATE_25KHZ) {
++ *dds = DDS_80000;
++ *clk_div = 124;
++ return BITRATE_25KHZ;
++ } else if (rate >= BITRATE_10KHZ) {
++ *dds = DDS_20000;
++ *clk_div = 77;
++ return BITRATE_10KHZ;
++ } else if (rate >= BITRATE_5KHZ) {
++ *dds = DDS_20000;
++ *clk_div = 154;
++ return BITRATE_5KHZ;
++ } else if (rate >= BITRATE_1KHZ) {
++ *dds = DDS_8000;
++ *clk_div = 194;
++ return BITRATE_1KHZ;
++ }
++ } else {
++ *dds = DDS_8000;
++ *clk_div = 194;
++ return BITRATE_MIN;
++ }
++ return 0;
++}
++#else
++/* this returns the value that SCR needs to be set to
++ Bit rate = DDS_FREQ / (2 x (SCR + 1)) */
+ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
+ {
++#ifdef CONFIG_GEN3_SPI
++ unsigned long ssp_clk = spi_clk_get_rate(ssp->type);
++#else
+ unsigned long ssp_clk = clk_get_rate(ssp->clk);
++#endif
+
+- if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
++ if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP
++ || ssp->type == CE5X00_SSP)
+ return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
+ else
+ return ((ssp_clk / rate - 1) & 0xfff) << 8;
+ }
++#endif /* CONFIG_INTEL_QUARK_X1000_SOC */
+
+ static void pump_transfers(unsigned long data)
+ {
+@@ -934,7 +1419,11 @@ static void pump_transfers(unsigned long data)
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+ struct chip_data *chip = NULL;
++#ifndef CONFIG_INTEL_QUARK_X1000_SOC
+ struct ssp_device *ssp = drv_data->ssp;
++#else
++ u32 actual_speed = 0;
++#endif
+ void __iomem *reg = drv_data->ioaddr;
+ u32 clk_div = 0;
+ u8 bits = 0;
+@@ -947,8 +1436,11 @@ static void pump_transfers(unsigned long data)
+ /* Get current state information */
+ message = drv_data->cur_msg;
+ transfer = drv_data->cur_transfer;
++
+ chip = drv_data->cur_chip;
+
++ if (transfer->bits_per_word)
++ chip->n_bytes = (transfer->bits_per_word + 7)/8;
+ /* Handle for abort */
+ if (message->state == ERROR_STATE) {
+ message->status = -EIO;
+@@ -992,11 +1484,11 @@ static void pump_transfers(unsigned long data)
+ }
+
+ /* warn ... we force this to PIO mode */
+- if (printk_ratelimit())
+- dev_warn(&message->spi->dev, "pump_transfers: "
+- "DMA disabled for transfer length %ld "
+- "greater than %d\n",
+- (long)drv_data->len, MAX_DMA_LEN);
++ dev_warn_ratelimited(&message->spi->dev,
++ "pump_transfers: "
++ "DMA disabled for transfer length %ld "
++ "greater than %d\n",
++ (long)drv_data->len, MAX_DMA_LEN);
+ }
+
+ /* Setup the transfer state based on the type of transfer */
+@@ -1009,19 +1501,21 @@ static void pump_transfers(unsigned long data)
+ drv_data->n_bytes = chip->n_bytes;
+ drv_data->dma_width = chip->dma_width;
+ drv_data->tx = (void *)transfer->tx_buf;
+- drv_data->tx_end = drv_data->tx + transfer->len;
++ drv_data->tx_end = drv_data->tx
++ + (transfer->len/drv_data->n_bytes)*drv_data->n_bytes;
+ drv_data->rx = transfer->rx_buf;
+- drv_data->rx_end = drv_data->rx + transfer->len;
++ drv_data->rx_end = drv_data->rx
++ + (transfer->len/drv_data->n_bytes)*drv_data->n_bytes;
+ drv_data->rx_dma = transfer->rx_dma;
+ drv_data->tx_dma = transfer->tx_dma;
+- drv_data->len = transfer->len & DCMD_LENGTH;
++ drv_data->len = (transfer->len/drv_data->n_bytes)
++ * drv_data->n_bytes & DCMD_LENGTH;
+ drv_data->write = drv_data->tx ? chip->write : null_writer;
+ drv_data->read = drv_data->rx ? chip->read : null_reader;
+
+ /* Change speed and bit per word on a per transfer */
+ cr0 = chip->cr0;
+ if (transfer->speed_hz || transfer->bits_per_word) {
+-
+ bits = chip->bits_per_word;
+ speed = chip->speed_hz;
+
+@@ -1031,8 +1525,13 @@ static void pump_transfers(unsigned long data)
+ if (transfer->bits_per_word)
+ bits = transfer->bits_per_word;
+
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ actual_speed = qrk_set_clk_regvals
++ (speed, &chip->dds_rate, &clk_div);
++ clk_div = (clk_div << 8);
++#else
+ clk_div = ssp_get_clk_div(ssp, speed);
+-
++#endif
+ if (bits <= 8) {
+ drv_data->n_bytes = 1;
+ drv_data->dma_width = DCMD_WIDTH1;
+@@ -1061,18 +1560,32 @@ static void pump_transfers(unsigned long data)
+ if (set_dma_burst_and_threshold(chip, message->spi,
+ bits, &dma_burst,
+ &dma_thresh))
+- if (printk_ratelimit())
+- dev_warn(&message->spi->dev,
+- "pump_transfers: "
+- "DMA burst size reduced to "
+- "match bits_per_word\n");
++ dev_warn_ratelimited(&message->spi->dev,
++ "pump_transfers: "
++ "DMA burst size reduced to"
++ " match bits_per_word\n");
+ }
+
+- cr0 = clk_div
+- | SSCR0_Motorola
+- | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
+- | SSCR0_SSE
+- | (bits > 16 ? SSCR0_EDSS : 0);
++ switch (drv_data->ssp_type) {
++ case CE5X00_SSP:
++ chip->cr0 = clk_div
++ | CE5X00_SSCR0_Motorola
++ | CE5X00_SSCR0_DataSize(bits > 32 ?
++ 8 : bits)
++ | SSCR0_SSE;
++ break;
++ case CE4100_SSP:
++ case PXA25x_SSP:
++ default:
++ chip->cr0 = clk_div
++ | SSCR0_Motorola
++ | SSCR0_DataSize(bits > 16 ?
++ bits - 16 : bits)
++ | SSCR0_SSE
++ | (bits > 16 ? SSCR0_EDSS : 0);
++ }
++
++ cr0 = chip->cr0;
+ }
+
+ message->state = RUNNING_STATE;
+@@ -1138,7 +1651,7 @@ static void pump_transfers(unsigned long data)
+
+ /* Clear status and start DMA engine */
+ cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
+- write_SSSR(drv_data->clear_sr, reg);
++ write_sssr(drv_data->clear_sr, reg);
+ DCSR(drv_data->rx_channel) |= DCSR_RUN;
+ DCSR(drv_data->tx_channel) |= DCSR_RUN;
+ } else {
+@@ -1147,100 +1660,72 @@ static void pump_transfers(unsigned long data)
+
+ /* Clear status */
+ cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
+- write_SSSR_CS(drv_data, drv_data->clear_sr);
++ write_sssr_cs(drv_data, drv_data->clear_sr);
+ }
+
+ /* see if we need to reload the config registers */
+- if ((read_SSCR0(reg) != cr0)
+- || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
+- (cr1 & SSCR1_CHANGE_MASK)) {
++ if (drv_data->ssp_type == CE5X00_SSP) {
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ if (read_dds_rate(reg) != chip->dds_rate)
++ write_dds_rate(chip->dds_rate, reg);
++#endif
++ if ((read_sscr0(reg) != cr0)
++ || (read_sscr1(reg) & CE5X00_SSCR1_CHANGE_MASK) !=
++ (cr1 & CE5X00_SSCR1_CHANGE_MASK)) {
++ /* stop the SSP, and update the other bits */
++ write_sscr0(cr0 & ~SSCR0_SSE, reg);
++ if (!pxa25x_ssp_comp(drv_data))
++ write_ssto(chip->timeout, reg);
++ /* first set CR1 w/o interrupt and service enables */
++ write_sscr1(cr1 & CE5X00_SSCR1_CHANGE_MASK, reg);
++ /* restart the SSP */
++ write_sscr0(cr0, reg);
+
++ } else {
++ if (!pxa25x_ssp_comp(drv_data))
++ write_ssto(chip->timeout, reg);
++ }
++ } else if ((read_sscr0(reg) != cr0)
++ || (read_sscr1(reg) & SSCR1_CHANGE_MASK) !=
++ (cr1 & SSCR1_CHANGE_MASK)) {
+ /* stop the SSP, and update the other bits */
+- write_SSCR0(cr0 & ~SSCR0_SSE, reg);
++ write_sscr0(cr0 & ~SSCR0_SSE, reg);
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(chip->timeout, reg);
++ write_ssto(chip->timeout, reg);
+ /* first set CR1 without interrupt and service enables */
+- write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
++ write_sscr1(cr1 & SSCR1_CHANGE_MASK, reg);
+ /* restart the SSP */
+- write_SSCR0(cr0, reg);
++ write_sscr0(cr0, reg);
+
+- } else {
+- if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(chip->timeout, reg);
++ } else if (!pxa25x_ssp_comp(drv_data)) {
++ write_ssto(chip->timeout, reg);
+ }
+-
+ cs_assert(drv_data);
+
+ /* after chip select, release the data by enabling service
+ * requests and interrupts, without changing any mode bits */
+- write_SSCR1(cr1, reg);
++ write_sscr1(cr1, reg);
+ }
+
+-static void pump_messages(struct work_struct *work)
++static int transfer_one_message(struct spi_master *master,
++ struct spi_message *msg)
+ {
+- struct driver_data *drv_data =
+- container_of(work, struct driver_data, pump_messages);
+- unsigned long flags;
+-
+- /* Lock queue and check for queue work */
+- spin_lock_irqsave(&drv_data->lock, flags);
+- if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+- drv_data->busy = 0;
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+- return;
+- }
++ struct driver_data *drv_data = spi_master_get_devdata(master);
+
+- /* Make sure we are not already running a message */
+- if (drv_data->cur_msg) {
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+- return;
+- }
+-
+- /* Extract head of queue */
+- drv_data->cur_msg = list_entry(drv_data->queue.next,
+- struct spi_message, queue);
+- list_del_init(&drv_data->cur_msg->queue);
++ /* Initial message state */
++ drv_data->cur_msg = msg;
++ msg->state = START_STATE;
+
+- /* Initial message state*/
+- drv_data->cur_msg->state = START_STATE;
+- drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+- struct spi_transfer,
+- transfer_list);
++ drv_data->cur_transfer = list_entry(msg->transfers.next,
++ struct spi_transfer, transfer_list);
+
+ /* prepare to setup the SSP, in pump_transfers, using the per
+ * chip configuration */
+- drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
++ drv_data->cur_chip = spi_get_ctldata(msg->spi);
+
+- /* Mark as busy and launch transfers */
++ /* Launch transfers */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+- drv_data->busy = 1;
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+-}
+-
+-static int transfer(struct spi_device *spi, struct spi_message *msg)
+-{
+- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+- unsigned long flags;
+-
+- spin_lock_irqsave(&drv_data->lock, flags);
+-
+- if (drv_data->run == QUEUE_STOPPED) {
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+- return -ESHUTDOWN;
+- }
+-
+- msg->actual_length = 0;
+- msg->status = -EINPROGRESS;
+- msg->state = START_STATE;
+-
+- list_add_tail(&msg->queue, &drv_data->queue);
+-
+- if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+-
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+-
+ return 0;
+ }
+
+@@ -1267,8 +1752,9 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
+ if (gpio_is_valid(chip_info->gpio_cs)) {
+ err = gpio_request(chip_info->gpio_cs, "SPI_CS");
+ if (err) {
+- dev_err(&spi->dev, "failed to request chip select "
+- "GPIO%d\n", chip_info->gpio_cs);
++ dev_err(&spi->dev,
++ "failed to request chip select "
++ "GPIO%d\n", chip_info->gpio_cs);
+ return err;
+ }
+
+@@ -1282,6 +1768,31 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
+ return err;
+ }
+
++static int prepare_transfer_hardware(struct spi_master *master)
++{
++ struct driver_data *drv_data = spi_master_get_devdata(master);
++
++ /*
++ * Just make sure we have all we need to run the transfer by syncing
++ * with the runtime PM framework.
++ */
++ pm_runtime_get_sync(&drv_data->pdev->dev);
++ return 0;
++}
++
++static int unprepare_transfer_hardware(struct spi_master *master)
++{
++ struct driver_data *drv_data = spi_master_get_devdata(master);
++
++ /* nothing more to do - disable spi/ssp and power off */
++ write_sscr0(0, drv_data->ioaddr);
++ clk_disable(drv_data->ssp->clk);
++
++ pm_runtime_put(&drv_data->pdev->dev);
++
++ return 0;
++}
++
+ static int setup(struct spi_device *spi)
+ {
+ struct pxa2xx_spi_chip *chip_info = NULL;
+@@ -1289,21 +1800,29 @@ static int setup(struct spi_device *spi)
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ struct ssp_device *ssp = drv_data->ssp;
+ unsigned int clk_div;
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ u32 actual_speed;
++#endif
+ uint tx_thres = TX_THRESH_DFLT;
+ uint rx_thres = RX_THRESH_DFLT;
+-
+- if (!pxa25x_ssp_comp(drv_data)
++ if (drv_data->ssp_type == CE5X00_SSP) {
++ tx_thres = TX_THRESH_CE5X00_DFLT;
++ rx_thres = RX_THRESH_CE5X00_DFLT;
++ }
++ if ((!pxa25x_ssp_comp(drv_data) || pxa25x_ssp_comp(drv_data) == 2)
+ && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
+- dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
+- "b/w not 4-32 for type non-PXA25x_SSP\n",
+- drv_data->ssp_type, spi->bits_per_word);
++ dev_err(&spi->dev,
++ "failed setup: ssp_type=%d, bits/wrd=%d "
++ "b/w not 4-32 for type non-PXA25x_SSP\n",
++ drv_data->ssp_type, spi->bits_per_word);
+ return -EINVAL;
+- } else if (pxa25x_ssp_comp(drv_data)
++ } else if (pxa25x_ssp_comp(drv_data) == 1
+ && (spi->bits_per_word < 4
+ || spi->bits_per_word > 16)) {
+- dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
+- "b/w not 4-16 for type PXA25x_SSP\n",
+- drv_data->ssp_type, spi->bits_per_word);
++ dev_err(&spi->dev,
++ "failed setup: ssp_type=%d, bits/wrd=%d "
++ "b/w not 4-16 for type PXA25x_SSP\n",
++ drv_data->ssp_type, spi->bits_per_word);
+ return -EINVAL;
+ }
+
+@@ -1319,8 +1838,9 @@ static int setup(struct spi_device *spi)
+
+ if (drv_data->ssp_type == CE4100_SSP) {
+ if (spi->chip_select > 4) {
+- dev_err(&spi->dev, "failed setup: "
+- "cs number must not be > 4.\n");
++ dev_err(&spi->dev,
++ "failed setup: "
++ "cs number must not be > 4.\n");
+ kfree(chip);
+ return -EINVAL;
+ }
+@@ -1328,6 +1848,7 @@ static int setup(struct spi_device *spi)
+ chip->frm = spi->chip_select;
+ } else
+ chip->gpio_cs = -1;
++
+ chip->enable_dma = 0;
+ chip->timeout = TIMOUT_DFLT;
+ chip->dma_burst_size = drv_data->master_info->enable_dma ?
+@@ -1340,6 +1861,7 @@ static int setup(struct spi_device *spi)
+
+ /* chip_info isn't always needed */
+ chip->cr1 = 0;
++ chip->cr0 = 0;
+ if (chip_info) {
+ if (chip_info->timeout)
+ chip->timeout = chip_info->timeout;
+@@ -1353,9 +1875,6 @@ static int setup(struct spi_device *spi)
+ chip->cr1 = SSCR1_LBM;
+ }
+
+- chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
+- (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
+-
+ /* set dma burst and threshold outside of chip_info path so that if
+ * chip_info goes away after setting chip->enable_dma, the
+ * burst and threshold can still respond to changes in bits_per_word */
+@@ -1364,33 +1883,73 @@ static int setup(struct spi_device *spi)
+ if (set_dma_burst_and_threshold(chip, spi, spi->bits_per_word,
+ &chip->dma_burst_size,
+ &chip->dma_threshold)) {
+- dev_warn(&spi->dev, "in setup: DMA burst size reduced "
+- "to match bits_per_word\n");
++ dev_warn(&spi->dev,
++ "in setup: DMA burst size reduced "
++ "to match bits_per_word\n");
+ }
+ }
+-
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ actual_speed = qrk_set_clk_regvals(spi->max_speed_hz,
++ &chip->dds_rate, &clk_div);
++ clk_div = (clk_div << 8);
++#else
+ clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
++#endif
+ chip->speed_hz = spi->max_speed_hz;
+
+- chip->cr0 = clk_div
++ switch (drv_data->ssp_type) {
++ case CE5X00_SSP:
++ chip->cr0 = clk_div
++ | CE5X00_SSCR0_Motorola
++ | CE5X00_SSCR0_DataSize(spi->bits_per_word > 32 ?
++ 8 : spi->bits_per_word)
++ | SSCR0_SSE;
++ chip->threshold = (CE5X00_SSCR1_RxTresh(rx_thres)
++ & CE5X00_SSCR1_RFT) |
++ (CE5X00_SSCR1_TxTresh(tx_thres) & CE5X00_SSCR1_TFT);
++ break;
++ case CE4100_SSP:
++ case PXA25x_SSP:
++ default:
++ chip->cr0 = clk_div
+ | SSCR0_Motorola
+ | SSCR0_DataSize(spi->bits_per_word > 16 ?
+ spi->bits_per_word - 16 : spi->bits_per_word)
+ | SSCR0_SSE
+ | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
++ chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
++ (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
++ }
++
+ chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
++ | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0)
++ | (((spi->mode & SPI_LOOP) != 0) ? SSCR1_LBM : 0);
++#else
+ chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
+ | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
++#endif
+
+ /* NOTE: PXA25x_SSP _could_ use external clocking ... */
+ if (!pxa25x_ssp_comp(drv_data))
+- dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
++ dev_dbg(&spi->dev,
++ "%ld Hz actual, %s\n",
++#ifndef CONFIG_GEN3_SPI
+ clk_get_rate(ssp->clk)
++#else
++ spi_clk_get_rate(ssp->type)
++#endif
+ / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
+ chip->enable_dma ? "DMA" : "PIO");
+ else
+- dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
++ dev_dbg(&spi->dev,
++ "%ld Hz actual, %s\n",
++#ifndef CONFIG_GEN3_SPI
+ clk_get_rate(ssp->clk) / 2
++#else
++ spi_clk_get_rate(ssp->type) / 2
++#endif
+ / (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
+ chip->enable_dma ? "DMA" : "PIO");
+
+@@ -1405,7 +1964,9 @@ static int setup(struct spi_device *spi)
+ chip->read = u16_reader;
+ chip->write = u16_writer;
+ } else if (spi->bits_per_word <= 32) {
++#ifndef CONFIG_GEN3_SPI
+ chip->cr0 |= SSCR0_EDSS;
++#endif
+ chip->n_bytes = 4;
+ chip->dma_width = DCMD_WIDTH4;
+ chip->read = u32_reader;
+@@ -1438,94 +1999,6 @@ static void cleanup(struct spi_device *spi)
+ kfree(chip);
+ }
+
+-static int init_queue(struct driver_data *drv_data)
+-{
+- INIT_LIST_HEAD(&drv_data->queue);
+- spin_lock_init(&drv_data->lock);
+-
+- drv_data->run = QUEUE_STOPPED;
+- drv_data->busy = 0;
+-
+- tasklet_init(&drv_data->pump_transfers,
+- pump_transfers, (unsigned long)drv_data);
+-
+- INIT_WORK(&drv_data->pump_messages, pump_messages);
+- drv_data->workqueue = create_singlethread_workqueue(
+- dev_name(drv_data->master->dev.parent));
+- if (drv_data->workqueue == NULL)
+- return -EBUSY;
+-
+- return 0;
+-}
+-
+-static int start_queue(struct driver_data *drv_data)
+-{
+- unsigned long flags;
+-
+- spin_lock_irqsave(&drv_data->lock, flags);
+-
+- if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+- return -EBUSY;
+- }
+-
+- drv_data->run = QUEUE_RUNNING;
+- drv_data->cur_msg = NULL;
+- drv_data->cur_transfer = NULL;
+- drv_data->cur_chip = NULL;
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+-
+- queue_work(drv_data->workqueue, &drv_data->pump_messages);
+-
+- return 0;
+-}
+-
+-static int stop_queue(struct driver_data *drv_data)
+-{
+- unsigned long flags;
+- unsigned limit = 500;
+- int status = 0;
+-
+- spin_lock_irqsave(&drv_data->lock, flags);
+-
+- /* This is a bit lame, but is optimized for the common execution path.
+- * A wait_queue on the drv_data->busy could be used, but then the common
+- * execution path (pump_messages) would be required to call wake_up or
+- * friends on every SPI message. Do this instead */
+- drv_data->run = QUEUE_STOPPED;
+- while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+- msleep(10);
+- spin_lock_irqsave(&drv_data->lock, flags);
+- }
+-
+- if (!list_empty(&drv_data->queue) || drv_data->busy)
+- status = -EBUSY;
+-
+- spin_unlock_irqrestore(&drv_data->lock, flags);
+-
+- return status;
+-}
+-
+-static int destroy_queue(struct driver_data *drv_data)
+-{
+- int status;
+-
+- status = stop_queue(drv_data);
+- /* we are unloading the module or failing to load (only two calls
+- * to this routine), and neither call can handle a return value.
+- * However, destroy_workqueue calls flush_workqueue, and that will
+- * block until all work is done. If the reason that stop_queue
+- * timed out is that the work will never finish, then it does no
+- * good to call destroy_workqueue, so return anyway. */
+- if (status != 0)
+- return status;
+-
+- destroy_workqueue(drv_data->workqueue);
+-
+- return 0;
+-}
+-
+ static int pxa2xx_spi_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -1557,16 +2030,27 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
+ drv_data->ssp = ssp;
+
+ master->dev.parent = &pdev->dev;
++#ifdef CONFIG_OF
++#ifndef CONFIG_GEN3_SPI
+ master->dev.of_node = pdev->dev.of_node;
++#endif
++#endif
++
+ /* the spi->mode bits understood by this driver: */
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
++#else
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+-
++#endif
+ master->bus_num = pdev->id;
+ master->num_chipselect = platform_info->num_chipselect;
+ master->dma_alignment = DMA_ALIGNMENT;
+ master->cleanup = cleanup;
+ master->setup = setup;
+- master->transfer = transfer;
++ master->prepare_transfer_hardware = prepare_transfer_hardware;
++ master->transfer_one_message = transfer_one_message;
++ master->unprepare_transfer_hardware = unprepare_transfer_hardware;
++ master->rt = true;
+
+ drv_data->ssp_type = ssp->type;
+ drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
+@@ -1628,43 +2112,59 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
+ clk_enable(ssp->clk);
+
+ /* Load default SSP configuration */
+- write_SSCR0(0, drv_data->ioaddr);
+- write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
+- SSCR1_TxTresh(TX_THRESH_DFLT),
+- drv_data->ioaddr);
+- write_SSCR0(SSCR0_SCR(2)
+- | SSCR0_Motorola
+- | SSCR0_DataSize(8),
+- drv_data->ioaddr);
++ write_sscr0(0, drv_data->ioaddr);
++ switch (drv_data->ssp_type) {
++ case CE5X00_SSP:
++ write_sscr1(CE5X00_SSCR1_RxTresh(RX_THRESH_CE5X00_DFLT) |
++ CE5X00_SSCR1_TxTresh(TX_THRESH_CE5X00_DFLT),
++ drv_data->ioaddr);
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ /* using the Motorola SPI protocol and use 8 bit frame */
++ write_sscr0(CE5X00_SSCR0_Motorola
++ | CE5X00_SSCR0_DataSize(8),
++ drv_data->ioaddr);
++#else
++ /* default using Motorola SPI protocol and use 8 bit frame */
++ write_sscr0(SSCR0_SCR(2)
++ | CE5X00_SSCR0_Motorola
++ | CE5X00_SSCR0_DataSize(8),
++ drv_data->ioaddr);
++#endif
++ break;
++ case CE4100_SSP:
++ case PXA25x_SSP:
++ default:
++ write_sscr1(SSCR1_RxTresh(RX_THRESH_DFLT) |
++ SSCR1_TxTresh(TX_THRESH_DFLT),
++ drv_data->ioaddr);
++ write_sscr0(SSCR0_SCR(2)
++ | SSCR0_Motorola
++ | SSCR0_DataSize(8),
++ drv_data->ioaddr);
++ }
+ if (!pxa25x_ssp_comp(drv_data))
+- write_SSTO(0, drv_data->ioaddr);
+- write_SSPSP(0, drv_data->ioaddr);
++ write_ssto(0, drv_data->ioaddr);
++#ifndef CONFIG_GEN3_SPI
++ /*
++ * SSPSP register is resrved on the CEXXXX SOCs.
++ */
++ write_sspsp(0, drv_data->ioaddr);
++#endif
+
+- /* Initial and start queue */
+- status = init_queue(drv_data);
+- if (status != 0) {
+- dev_err(&pdev->dev, "problem initializing queue\n");
+- goto out_error_clock_enabled;
+- }
+- status = start_queue(drv_data);
+- if (status != 0) {
+- dev_err(&pdev->dev, "problem starting queue\n");
+- goto out_error_clock_enabled;
+- }
++ /* Initialise transfer pump */
++ tasklet_init(&drv_data->pump_transfers,
++ pump_transfers, (unsigned long)drv_data);
+
+ /* Register with the SPI framework */
+ platform_set_drvdata(pdev, drv_data);
+ status = spi_register_master(master);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem registering spi master\n");
+- goto out_error_queue_alloc;
++ goto out_error_clock_enabled;
+ }
+
+ return status;
+
+-out_error_queue_alloc:
+- destroy_queue(drv_data);
+-
+ out_error_clock_enabled:
+ clk_disable(ssp->clk);
+
+@@ -1687,28 +2187,13 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
+ {
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ struct ssp_device *ssp;
+- int status = 0;
+
+ if (!drv_data)
+ return 0;
+ ssp = drv_data->ssp;
+
+- /* Remove the queue */
+- status = destroy_queue(drv_data);
+- if (status != 0)
+- /* the kernel does not check the return status of this
+- * this routine (mod->exit, within the kernel). Therefore
+- * nothing is gained by returning from here, the module is
+- * going away regardless, and we should not leave any more
+- * resources allocated than necessary. We cannot free the
+- * message memory in drv_data->queue, but we can release the
+- * resources below. I think the kernel should honor -EBUSY
+- * returns but... */
+- dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
+- "complete, message memory not freed\n");
+-
+ /* Disable the SSP at the peripheral and SOC level */
+- write_SSCR0(0, drv_data->ioaddr);
++ write_sscr0(0, drv_data->ioaddr);
+ clk_disable(ssp->clk);
+
+ /* Release DMA */
+@@ -1725,6 +2210,9 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
+ /* Release SSP */
+ pxa_ssp_free(ssp);
+
++ /* Disable transfer pump */
++ tasklet_disable(&drv_data->pump_transfers);
++
+ /* Disconnect from the SPI framework */
+ spi_unregister_master(drv_data->master);
+
+@@ -1738,7 +2226,8 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev)
+ {
+ int status = 0;
+
+- if ((status = pxa2xx_spi_remove(pdev)) != 0)
++ status = pxa2xx_spi_remove(pdev);
++ if (status != 0)
+ dev_err(&pdev->dev, "shutdown failed with %d\n", status);
+ }
+
+@@ -1749,10 +2238,15 @@ static int pxa2xx_spi_suspend(struct device *dev)
+ struct ssp_device *ssp = drv_data->ssp;
+ int status = 0;
+
+- status = stop_queue(drv_data);
+- if (status != 0)
++ status = spi_master_suspend(drv_data->master);
++ if (status) {
++ dev_warn(dev, "cannot suspend master\n");
+ return status;
+- write_SSCR0(0, drv_data->ioaddr);
++ }
++
++ pm_runtime_get_sync(dev);
++
++ write_sscr0(0, drv_data->ioaddr);
+ clk_disable(ssp->clk);
+
+ return 0;
+@@ -1774,14 +2268,14 @@ static int pxa2xx_spi_resume(struct device *dev)
+ /* Enable the SSP clock */
+ clk_enable(ssp->clk);
+
++ pm_runtime_put(dev);
++
+ /* Start the queue running */
+- status = start_queue(drv_data);
+- if (status != 0) {
++ status = spi_master_resume(drv_data->master);
++ if (status)
+ dev_err(dev, "problem starting queue (%d)\n", status);
+- return status;
+- }
+
+- return 0;
++ return status;
+ }
+
+ static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
+diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h
+index f366320..9810c71 100644
+--- a/include/linux/pxa2xx_ssp.h
++++ b/include/linux/pxa2xx_ssp.h
+@@ -104,6 +104,28 @@
+ #define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
+ #define SSCR1_RFT (0x00000c00) /* Receive FIFO Threshold (mask) */
+ #define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
++
++/* CE5X00 SSCR0 bit definition */
++#define CE5X00_SSCR0_DSS ((1<<5)-1) /* Data Size Select (mask) */
++#define CE5X00_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */
++#define CE5X00_SSCR0_FRF (((1<<2)-1) << 5) /* FRame Format (mask) */
++#define CE5X00_SSCR0_Motorola (0x0 << 5) /* Motorola's Serial Peripheral Interface (SPI) */
++#define CE5X00_SSCR0_TI (0x1 << 5) /* Texas Instruments' Synchronous Serial Protocol (SSP) */
++#define CE5X00_SSCR0_National (0x2 << 5) /* National Microwire */
++
++#define RX_THRESH_CE5X00_DFLT 16
++#define TX_THRESH_CE5X00_DFLT 16
++
++#define CE5X00_SSSR_TFL_MASK (0x1F << 8) /* Transmit FIFO Level mask */
++#define CE5X00_SSSR_RFL_MASK (0x1F << 13) /* Receive FIFO Level mask */
++
++#define CE5X00_SSCR1_TFT (((1<<5)-1) << 6) /* Transmit FIFO Threshold (mask) */
++#define CE5X00_SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..32] */
++#define CE5X00_SSCR1_RFT (((1<<5)-1) << 11) /* Receive FIFO Threshold (mask) */
++#define CE5X00_SSCR1_RxTresh(x) (((x) - 1) << 11) /* level [1..32] */
++#define CE5X00_SSCR1_STRF (1 << 17) /* Select FIFO or EFWR */
++#define CE5X00_SSCR1_EFWR (1 << 16) /* Enable FIFO Write/Read */
++
+ #endif
+
+ /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
+@@ -164,6 +186,7 @@ enum pxa_ssp_type {
+ PXA168_SSP,
+ PXA910_SSP,
+ CE4100_SSP,
++ CE5X00_SSP,
+ };
+
+ struct ssp_device {
+@@ -181,6 +204,7 @@ struct ssp_device {
+ int irq;
+ int drcmr_rx;
+ int drcmr_tx;
++ struct pci_dev *pcidev;
+ };
+
+ /**
+@@ -208,4 +232,5 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
+
+ struct ssp_device *pxa_ssp_request(int port, const char *label);
+ void pxa_ssp_free(struct ssp_device *);
++int pxa_msi_enabled(void);
+ #endif
+diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h
+index c73d144..acac9ae 100644
+--- a/include/linux/spi/pxa2xx_spi.h
++++ b/include/linux/spi/pxa2xx_spi.h
+@@ -130,23 +130,12 @@ static inline void pxa_free_dma(int dma_ch)
+ {
+ }
+
+-/*
+- * The CE4100 does not have the clk framework implemented and SPI clock can
+- * not be switched on/off or the divider changed.
+- */
+-static inline void clk_disable(struct clk *clk)
+-{
+-}
+-
+-static inline int clk_enable(struct clk *clk)
+-{
+- return 0;
+-}
+-
++#ifndef CONFIG_GEN3_SPI
+ static inline unsigned long clk_get_rate(struct clk *clk)
+ {
+ return 3686400;
+ }
++#endif
+
+ #endif
+ #endif
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index f629189..307d218 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -80,6 +80,8 @@ struct spi_device {
+ #define SPI_MODE_2 (SPI_CPOL|0)
+ #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
+ #define SPI_CS_HIGH 0x04 /* chipselect active high? */
++#define SPI_MODE_QUAD_IO 0x05 /* Quad IO mode using 4 wire */
++#define SPI_MODE_DUAL_IO 0x06 /* Dual IO mode using 2 wire */
+ #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
new file mode 100644
index 0000000..809c203
--- /dev/null
+++ b/recipes-kernel/linux/files/0020-Quark-IIO-quark.patch
@@ -0,0 +1,2742 @@
+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
+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/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(-)
+ 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/max78m6610_lmu.h
+
+diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
+index b34d754..60491e4 100644
+--- a/drivers/iio/adc/ad7298.c
++++ b/drivers/iio/adc/ad7298.c
+@@ -33,7 +33,6 @@
+ #define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
+ #define AD7298_PDD (1 << 0) /* partial power down enable */
+
+-#define AD7298_MAX_CHAN 8
+ #define AD7298_BITS 12
+ #define AD7298_STORAGE_BITS 16
+ #define AD7298_INTREF_mV 2500
+@@ -46,6 +45,7 @@ struct ad7298_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned ext_ref;
++ u16 ext_vin_max[AD7298_MAX_CHAN];
+ struct spi_transfer ring_xfer[10];
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message ring_msg;
+@@ -64,7 +64,7 @@ struct ad7298_state {
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
++ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+@@ -269,7 +269,10 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+- *val = ad7298_get_ref_voltage(st);
++ if (st->ext_vin_max[chan->channel])
++ *val = st->ext_vin_max[chan->channel];
++ else
++ *val = ad7298_get_ref_voltage(st);
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+@@ -304,8 +307,15 @@ static int ad7298_probe(struct spi_device *spi)
+
+ st = iio_priv(indio_dev);
+
+- if (pdata && pdata->ext_ref)
+- st->ext_ref = AD7298_EXTREF;
++ if (pdata) {
++ int i;
++
++ if (pdata->ext_ref)
++ st->ext_ref = AD7298_EXTREF;
++
++ for (i = 0; i < AD7298_MAX_CHAN; i++)
++ st->ext_vin_max[i] = pdata->ext_vin_max[i];
++ }
+
+ 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
+--- a/drivers/staging/iio/adc/Kconfig
++++ b/drivers/staging/iio/adc/Kconfig
+@@ -137,4 +137,17 @@ config SPEAR_ADC
+ Say yes here to build support for the integrated ADC inside the
+ ST SPEAr SoC. Provides direct access via sysfs.
+
++config MAX78M6610_LMU
++ tristate "Maxim 78M6610+LMU driver"
++ depends on SPI
++ select IIO_BUFFER
++ select IIO_TRIGGERED_BUFFER
++ help
++ Say yes here to build support for Maxim Energy Measurement Processor
++ for Load Monitoring Units.
++
++ To compile this driver as a module, choose M here: the
++ module will be called max78m6610_lmu.
++
++
+ endmenu
+diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
+index d285596..2c4e7e1 100644
+--- a/drivers/staging/iio/adc/Makefile
++++ b/drivers/staging/iio/adc/Makefile
+@@ -21,3 +21,4 @@ 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
+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
+--- /dev/null
++++ b/drivers/staging/iio/adc/max78m6610_lmu.c
+@@ -0,0 +1,2235 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * 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
++ * Quark Evaluation Boards Cross Hill Industrial-E.
++ *
++ * The Maxim 78M6610+LMU is an energy measurement processor (EMP) for
++ * load monitoring on single or spilt-phase AC loads. It supports varies
++ * interface configuration protocols through I/O pins.
++ *
++ * With 3 wire serial input/output interfaces provided by Quark SoC,
++ * the 78M6610+LMU can be connected directly as SPI slave device.
++ */
++
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/fs.h>
++#include <linux/gpio.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/buffer.h>
++#include <linux/iio/types.h>
++#include <linux/iio/trigger.h>
++#include <linux/iio/trigger_consumer.h>
++#include <linux/iio/triggered_buffer.h>
++#include <linux/iio/sysfs.h>
++#include <linux/iio/events.h>
++#include <linux/platform_data/max78m6610_lmu.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spidev.h>
++#include <linux/version.h>
++
++/* Calibration registers */
++#define COMMAND 0x00 /* Command Register */
++#define SAMPLES 0x03 /* High-rate samples per low-rate */
++#define CALCYCS 0x04 /* Number of Calibration Cycles to Average */
++#define PHASECOMP1 0x05 /* Phase compensation for S1 input */
++#define PHASECOMP3 0x06 /* Phase compensation for S3 input */
++#define S1_GAIN 0x07 /* Input S1 Gain Calibration */
++#define S0_GAIN 0x08 /* Input S0 Gain Calibration */
++#define S3_GAIN 0x09 /* Input S3 Gain Calibration */
++#define S2_GAIN 0x0A /* Input S2 Gain Calibration */
++#define S1_OFFSET 0x0D /* Input S1 Offset Calibration */
++#define S0_OFFSET 0x0B /* Input S0 Offset Calibration */
++#define S3_OFFSET 0x0E /* Input S3 Offset Calibration */
++#define S2_OFFSET 0x0C /* Input S2 Offset Calibration */
++#define VTARGET 0x12 /* Voltage Calibration Target */
++#define ITARGET 0x39 /* Current Calibration Target */
++
++#define CALCMD_S0_GAIN 0xCA2030 /* Calibrate Voltage Gain for Input S0 */
++#define CALCMD_S1_GAIN 0xCA0830 /* Calibrate Current Gain for Input S1 */
++#define CALCMD_S2_GAIN 0xCA4030 /* Calibrate Voltage Gain for Input S2 */
++#define CALCMD_S3_GAIN 0xCA1030 /* Calibrate Current Gain for Input S3 */
++#define CALCMD_S0_OFFS 0xCA2210 /* Calibrate Voltage Offset for Input S0 */
++#define CALCMD_S1_OFFS 0xCA0A10 /* Calibrate Current Offset for Input S1 */
++#define CALCMD_S2_OFFS 0xCA4210 /* Calibrate Voltage Offset for Input S2 */
++#define CALCMD_S3_OFFS 0xCA1210 /* Calibrate Current Offset for Input S3 */
++#define FLASHSAVE_CMD 0xACC210 /* Save calibration coefficients to flash */
++
++/* Interrupt status registers */
++#define MASK0 0x02 /* Status bit mask for MP0 pin */
++#define STATUS 0x0F /* Status of device and alarms */
++#define STATUS_RESET 0x11 /* Used to Reset Status bits */
++#define STATUS_MASK_DRDY (1 << 23)
++#define STATUS_MASK_MMUPD (1 << 22)
++#define STATUS_MASK_VA_SAG (1 << 21)
++#define STATUS_MASK_VB_SAG (1 << 20)
++#define STATUS_MASK_SIGN_VA (1 << 19)
++#define STATUS_MASK_SIGN_VB (1 << 18)
++#define STATUS_MASK_OV_TEMP (1 << 17)
++#define STATUS_MASK_UN_TEMP (1 << 16)
++#define STATUS_MASK_OV_FREQ (1 << 15)
++#define STATUS_MASK_UN_FREQ (1 << 14)
++#define STATUS_MASK_OV_VRMSA (1 << 13)
++#define STATUS_MASK_UN_VRMSA (1 << 12)
++#define STATUS_MASK_OV_VRMSB (1 << 11)
++#define STATUS_MASK_UN_VRMSB (1 << 10)
++#define STATUS_MASK_VA_SURGE (1 << 9)
++#define STATUS_MASK_VB_SURGE (1 << 8)
++#define STATUS_MASK_OV_WATT1 (1 << 7)
++#define STATUS_MASK_OV_WATT2 (1 << 6)
++#define STATUS_MASK_OV_AMP1 (1 << 5)
++#define STATUS_MASK_OV_AMP2 (1 << 4)
++#define STATUS_MASK_XSTATE (1 << 3)
++#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 VSURG_VAL 0x13 /* Voltage surge alarm threshold */
++#define VSAG_VAL 0x14 /* Voltage sag alarm threshold */
++#define VRMS_MIN 0x15 /* Voltage lower alarm limit */
++#define VRMS_MAX 0x16 /* Voltage upper alarm limit */
++#define IRMS_MAX 0x27 /* Over Current alarm limit */
++#define WATT_MAX 0x32 /* Power alarm limit */
++
++#define INSTAN_VA 0x1D /* instaneous Voltage for VA source */
++#define INSTAN_IA 0x25 /* instaneous Current for IA source */
++#define INSTAN_PA 0x2E /* instaneous Active Power for source A*/
++#define INSTAN_PQA 0x30 /* instaneous Reactive Power for source A*/
++#define VA_RMS 0x17 /* RMS voltage for VA source */
++#define IA_RMS 0x1F /* RMS current for VA source */
++#define WATT_A 0x28 /* Active Power for source A */
++#define VAR_A 0x2C /* Reactive power for source A */
++#define VA_A 0x2A /* Volt-Amperes for source A */
++#define PFA 0x33 /* Source A Power Factor */
++
++#define INSTAN_VB 0x1E /* instaneous Voltage for VB source */
++#define INSTAN_IB 0x26 /* instaneous Current for IB source */
++#define INSTAN_PB 0x2F /* instaneous Active Power for source B*/
++#define INSTAN_PQB 0x31 /* instaneous Voltage for VB source */
++#define VB_RMS 0x18 /* RMS voltage for VB source */
++#define IB_RMS 0x20 /* RMS current for VB source */
++#define WATT_B 0x29 /* Active Power for source B */
++#define VAR_B 0x2D /* Reactive power for source B */
++#define VA_B 0x2B /* Volt-amperes for source B */
++#define PFB 0x34 /* Source B Power Factor */
++
++/* Addr bit 6-7: ADDR6, ADDR7 */
++#define SPI_CB_ADDR_MASK_7_6(x) (((x) & 0xC0) >> 6)
++/* Addr bit 0 - 5 */
++#define SPI_TB_ADDR_MASK_5_0(x) ((x) & 0x3F)
++
++#define SPI_CB_NBR_ACC 0x00 /* number register of accesss, limit to 1 */
++#define SPI_CB_CMD 0x01 /* SPI command flag */
++#define SPI_OP_READ 0x00 /* bit 1: Read/Write RD:0 W:1 */
++#define SPI_OP_WRITE 0x02 /* bit 1: Read/Write RD:0 W:1 */
++/* Positive / negative conversion */
++#define SIGN_CONVERT 0xFFFFFFFFFFFFFFFF
++#define DATA_BIT_MASK 0x00FFFFFF
++#define SIGN_BIT_NUM 23
++#define SPI_MSG_LEN 5
++#define RX_OFFSET 1
++#define SPI_BBUFFER_LEN 4096
++/* All registers on the device are 24-bit */
++#define REG_WIDTH 24
++#define SAMPLE_INTERVAL_USEC 250 /* High-rate sample interval (microseconds) */
++#define RESET_DELAY_MSEC 100
++#define INTR_GPIO 2
++
++/* SPI message Control byte */
++#define SPI_CB(x) ((SPI_CB_NBR_ACC << 4)\
++ | (SPI_CB_ADDR_MASK_7_6(x) << 2)\
++ | SPI_CB_CMD)
++/* SPI message Transaction byte */
++#define SPI_TB_READ(x) ((SPI_TB_ADDR_MASK_5_0(x) << 2)\
++ | SPI_OP_READ)
++#define SPI_TB_WRITE(x) ((SPI_TB_ADDR_MASK_5_0(x) << 2)\
++ | SPI_OP_WRITE)
++
++/**
++ * max78m6610_lmu_channels structure maps eADC measurement features to
++ * IIO channels on the IIO sysfs user interface
++ */
++static const struct iio_chan_spec max78m6610_lmu_channels[] = {
++ /* IIO Channels for source A */
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "inst",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_VA,
++ .scan_index = 0,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "rms",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = IA_RMS,
++ .scan_index = 1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "inst_act",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_PA,
++ .scan_index = 2,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "inst_react",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_PQA,
++ .scan_index = 3,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "avg_act",
++ /* IIO_CHAN_INFO_AVERAGE_RAW is not used here,
++ * this average value is provide by HW register,
++ */
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = WATT_A,
++ .scan_index = 4,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "avg_react",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = VAR_A,
++ .scan_index = 5,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "apparent",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = VA_A,
++ .scan_index = 6,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "factor",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = PFA,
++ .scan_index = 7,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32, /* data type S.22 */
++ .storagebits = 32,
++ .shift = 22,
++ },
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "rms",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = VA_RMS,
++ .scan_index = 8,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++
++ /* IIO channels for source B */
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "inst",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_VB,
++ .scan_index = 9,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "rms",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = IB_RMS,
++ .scan_index = 10,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "inst_act",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_PB,
++ .scan_index = 11,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "inst_react",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_PQB,
++ .scan_index = 12,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "avg_act",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = WATT_B,
++ .scan_index = 13,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "avg_react",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = VAR_B,
++ .scan_index = 14,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "apparent",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = VA_B,
++ .scan_index = 15,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "factor",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = PFB,
++ .scan_index = 16,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 22, /* data type S.22 */
++ },
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "rms",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = VB_RMS,
++ .scan_index = 17,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "inst",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_IA,
++ .scan_index = 18,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "inst",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
++ IIO_CHAN_INFO_SCALE_SHARED_BIT,
++ .address = INSTAN_IB,
++ .scan_index = 19,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "phasecomp",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = PHASECOMP1,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 21,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "phasecomp",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = PHASECOMP3,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 21,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "calib_target_rms",
++ .info_mask = IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_RAW),
++ .address = VTARGET,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "calib_target_rms",
++ .info_mask = IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_RAW),
++ .address = ITARGET,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "calib_gain",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S0_GAIN,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 21,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "calib_gain",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S2_GAIN,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 21,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "calib_gain",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S1_GAIN,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 21,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "calib_gain",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S3_GAIN,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 21,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "calib_offset",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S0_OFFSET,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "calib_offset",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S2_OFFSET,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 0,
++ .extend_name = "calib_offset",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S1_OFFSET,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 1,
++ .channel = 1,
++ .extend_name = "calib_offset",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = S3_OFFSET,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 0,
++ .channel = 0,
++ .extend_name = "surge_threshold",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = VSURG_VAL,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 0,
++ .channel = 0,
++ .extend_name = "sag_threshold",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = VSAG_VAL,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 0,
++ .channel = 0,
++ .extend_name = "rms_min_threshold",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = VRMS_MIN,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_VOLTAGE,
++ .indexed = 0,
++ .channel = 0,
++ .extend_name = "rms_max_threshold",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = VRMS_MAX,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_CURRENT,
++ .indexed = 0,
++ .channel = 0,
++ .extend_name = "rms_max_threshold",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = IRMS_MAX,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++ {
++ .type = IIO_POWER,
++ .indexed = 0,
++ .channel = 0,
++ .extend_name = "active_max_threshold",
++ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
++ .address = WATT_MAX,
++ .scan_index = -1,
++ .scan_type = {
++ .sign = 's',
++ .realbits = 32,
++ .storagebits = 32,
++ .shift = 23,
++ },
++ .output = 1,
++ },
++
++ IIO_CHAN_SOFT_TIMESTAMP(20),
++};
++
++/* max number of iio channels */
++#define MAX_CHAN_NUM ARRAY_SIZE(max78m6610_lmu_channels)
++
++/* eADC state structure */
++struct max78m6610_lmu_state {
++ struct spi_device *spi;
++ struct iio_dev_attr *iio_attr;
++ struct iio_trigger *trig;
++ struct spi_transfer ring_xfer[MAX_CHAN_NUM];
++ struct spi_transfer scan_single_xfer;
++ struct spi_message ring_msg;
++ struct spi_message scan_single_msg;
++
++ u8 tx_buf[SPI_MSG_LEN * MAX_CHAN_NUM];
++ u8 rx_buf[SPI_MSG_LEN * MAX_CHAN_NUM + sizeof(s64)];
++
++ int reset_gpio;
++
++ /* Char dev to provide ioctl interface for f/w upgrade
++ * or low-level register access */
++ struct cdev cdev;
++ dev_t cdev_no;
++ struct class *cl;
++ u8 *bbuffer;
++};
++
++/**
++ * ret_fraction_log2
++ *
++ * @param val: pointer to val
++ * @param val2: pointer to val2
++ * @return: no returns
++ *
++ * this function to re-implement of IIO_VAL_FRACTIONAL_LOG2 marco in IIO
++ * because of the do_div() function is not correctly handle the negative
++ * input value.
++ */
++static void ret_fraction_log2(int *val, int *val2)
++{
++ s64 tmp;
++
++ tmp = *val;
++
++ if (*val < 0) {
++ /* the do_div function will return trash if the value
++ * of input is negative. We need to treat tmp as
++ * a positive number for calculation.
++ * 1. XOR tmp with 0xFFFFFFFFFFFFFFFF.
++ * 2. add on the differential
++ */
++ tmp = (tmp ^ SIGN_CONVERT) + 1;
++ tmp = tmp * 1000000000LL >> (*val2);
++ *val2 = do_div(tmp, 1000000000LL);
++ *val = tmp;
++ /* the IIO_VAL_INT_PLUS_NANO marco is used in the later stage
++ * to return the proper format of output.
++ * The IIO use the value of val2 to determinate the sign
++ * of the output.
++ * Convert val2 from positive to negative to fool IIO to
++ * display the
++ * correct output format.
++ */
++ *val2 = *val2 ^ SIGN_CONVERT;
++ } else {
++
++ tmp = tmp * 1000000000LL >> (*val2);
++ *val2 = do_div(tmp, 1000000000LL);
++ *val = tmp;
++ }
++}
++
++/**
++ * intplusnano_to_regval
++ *
++ * @param val_int: Integer part of floating point value
++ * @param val_nano: Fractional part of floating point value
++ * @param frac_bits: The number of fractional bits to produce for this register
++ * @param regval: The resulting 24-bit signed fixed-point register value
++ * @return: 0 on success, non-zero on error
++ *
++ * As the kernel doesn't allow floating point numbers, IIO
++ * will split them into separate integer and fractional parts. This function
++ * then converts them into fixed-point signed register values for the MAX78M6610
++ */
++static int intplusnano_to_regval(int val_int, int val_nano,
++ int fract_bits, u32 *regval)
++{
++ int i, max_int, negative = 0;
++
++ /* Maximum integer value must be 24 bits minus sign and fraction_bits */
++ max_int = 1 << (REG_WIDTH - fract_bits - 1);
++
++ if ((val_int >= max_int) ||
++ (val_int < -max_int) ||
++ ((val_int == -max_int) && (val_nano != 0))) {
++ pr_err("Input value exceeds maximum allowed range\n");
++ return -EINVAL;
++ }
++
++ *regval = abs(val_int) << fract_bits;
++
++ /* Set the sign-bit, if input is negative */
++ if ((val_int < 0) || (val_nano < 0))
++ negative = 1;
++
++ val_nano = abs(val_nano);
++
++ /* Divide the fractional part down by negative powers of 2*/
++ for (i = fract_bits-1; i >= 0 && val_nano; i--) {
++ val_nano = val_nano << 1;
++ if (val_nano >= 1000000000LL) {
++ *regval |= (1 << i);
++ val_nano -= 1000000000LL;
++ }
++ }
++
++ /* Get 2s complement of number if negative */
++ if (negative)
++ *regval = (~(*regval) + 1) & ((1 << REG_WIDTH) - 1);
++
++ return 0;
++}
++
++/**
++ * __max78m6610_lmu_spi_reg_read
++ *
++ * @param st: Driver state data
++ * @param regaddr: The register word address to read
++ * @param regval: The 24-bit register value obtained by the read operation
++ * @return: 0 on success, non-zero on error
++ *
++ * Issues a SPI transaction to read a single register on the device.
++ * Performs endian byte swap before returning the register data.
++ */
++static inline
++int __max78m6610_lmu_spi_reg_read(struct max78m6610_lmu_state *st,
++ u8 regaddr,
++ u32 *regval)
++{
++ int ret;
++
++ st->tx_buf[0] = SPI_CB(regaddr);
++ st->tx_buf[1] = SPI_TB_READ(regaddr);
++ ret = spi_sync(st->spi, &st->scan_single_msg);
++ if (ret) {
++ pr_err("spi_sync return error: %d\n", ret);
++ return -EIO;
++ }
++
++ *regval = (st->rx_buf[2] << 16) | (st->rx_buf[3] << 8) | st->rx_buf[4];
++
++ return 0;
++}
++
++/**
++ * __max78m6610_lmu_spi_reg_write
++ *
++ * @param st: Driver state data
++ * @param regaddr: The register word address to write
++ * @param regval: The 24-bit value to write to the register
++ * @return: 0 on success, non-zero on error
++ *
++ * Issues a SPI transaction to write a single register on the device.
++ * Performs endian byte swap before writing the register data.
++ */
++static inline
++int __max78m6610_lmu_spi_reg_write(struct max78m6610_lmu_state *st,
++ u8 regaddr,
++ u32 regval)
++{
++ int ret;
++
++ st->tx_buf[0] = SPI_CB(regaddr);
++ st->tx_buf[1] = SPI_TB_WRITE(regaddr);
++ st->tx_buf[2] = regval >> 16;
++ st->tx_buf[3] = regval >> 8;
++ st->tx_buf[4] = regval & 0xFF;
++
++ ret = spi_sync(st->spi, &st->scan_single_msg);
++ if (ret) {
++ pr_err("spi_sync return non-zero value\n");
++ ret = -EIO;
++ }
++
++ return 0;
++}
++
++/**
++ * max78m6610_lmu_update_scan_mode
++ *
++ * @param indio_dev: iio_dev pointer.
++ * @param active_scan_mask: pointer to scan mask.
++ * @return 0 on success or standard errnos on failure
++ *
++ * setup the spi transfer buffer for the actived scan mask
++ **/
++static int max78m6610_lmu_update_scan_mode(struct iio_dev *indio_dev,
++ const unsigned long *active_scan_mask)
++{
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++ int i, tx = 0, k = 0;
++ unsigned addr;
++
++ spi_message_init(&st->ring_msg);
++
++ /* scan through all the channels */
++ for (i = 0; i < MAX_CHAN_NUM; i++) {
++ /* we build the the spi message here that support
++ * multiple register access request on the selected channel */
++ if (test_bit(i, active_scan_mask)) {
++ addr = max78m6610_lmu_channels[i].address;
++ /* first two bytes are the contol bytes */
++ st->tx_buf[tx] = SPI_CB(addr);
++ st->tx_buf[tx+1] = SPI_TB_READ(addr);
++
++ st->ring_xfer[k].cs_change = 0;
++ st->ring_xfer[k].tx_buf = &st->tx_buf[tx];
++ /* rx buffer */
++ /* All the HW registers in the HW are designed as 24 bit
++ * size, so we skip the first byte in the rx_buf when
++ * constructing the ring_xfer.
++ */
++ st->ring_xfer[k].rx_buf = &st->rx_buf[tx];
++ st->ring_xfer[k].len = SPI_MSG_LEN;
++ st->ring_xfer[k].cs_change = 1;
++
++ spi_message_add_tail(&st->ring_xfer[k],
++ &st->ring_msg);
++ /* update in bytes number */
++ tx += SPI_MSG_LEN;
++ k++;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * max78m6610_lmu_trigger_handle
++ *
++ * @param irq: irq indicator
++ * @parma p: iio pull funciton pointer
++ * @return IRQ_HANDLED
++ *
++ * bh handler of trigger launched polling to ring buffer
++ *
++ **/
++static irqreturn_t max78m6610_lmu_trigger_handler(int irq, void *p)
++{
++ struct iio_poll_func *pf = p;
++ struct iio_dev *indio_dev = pf->indio_dev;
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++
++ u32 scan_buf[((sizeof(u32)*MAX_CHAN_NUM)+sizeof(s64))/sizeof(u32)];
++ s64 time_ns = 0;
++ int b_sent;
++ int i = 0, rx_bit = 0;
++ int scan_count;
++
++ b_sent = spi_sync(st->spi, &st->ring_msg);
++ if (b_sent) {
++ pr_err("spi_sync failed.\n");
++ goto done;
++ }
++
++ scan_count = bitmap_weight(indio_dev->active_scan_mask,
++ indio_dev->masklength);
++
++ if (indio_dev->scan_timestamp) {
++ time_ns = iio_get_time_ns();
++ memcpy((u8 *)scan_buf + indio_dev->scan_bytes - sizeof(s64),
++ &time_ns, sizeof(time_ns));
++ }
++
++ for (i = 0; i < scan_count; i++) {
++ u32 *rx_buf_32 = NULL;
++ rx_bit = i*SPI_MSG_LEN + RX_OFFSET;
++ rx_buf_32 = (u32 *)&(st->rx_buf[rx_bit]);
++ *rx_buf_32 = be32_to_cpu(*rx_buf_32) & DATA_BIT_MASK;
++ scan_buf[i] = sign_extend32(*rx_buf_32,
++ SIGN_BIT_NUM);
++ }
++
++ iio_push_to_buffers(indio_dev, (u8 *)scan_buf);
++done:
++ iio_trigger_notify_done(indio_dev->trig);
++
++ return IRQ_HANDLED;
++}
++
++/**
++ * max78m6610_lmu_read_raw
++ *
++ * @param indio_dev: iio_dev pointer
++ * @param chan: pointer to iio channel spec struct
++ * @param val: return value pointer
++ * @param val2: return value 2 ponter
++ * @parma m: read mask
++ * @return: IIO value type
++ *
++ * This function will be invoked when request a value form the device.
++ * Read mask specifies which value, return value will specify the type of
++ * value returned from device, val and val2 will contains the elements
++ * making up the return value.
++ */
++static int max78m6610_lmu_read_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int *val,
++ int *val2,
++ long m)
++{
++ int ret;
++ u32 regval;
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++
++ switch (m) {
++
++ case IIO_CHAN_INFO_RAW:
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ mutex_unlock(&indio_dev->mlock);
++ return -EBUSY;
++ }
++
++ ret = __max78m6610_lmu_spi_reg_read(st, chan->address, &regval);
++ mutex_unlock(&indio_dev->mlock);
++ if (ret)
++ return ret;
++
++ *val = sign_extend32(regval, SIGN_BIT_NUM);
++ *val2 = chan->scan_type.shift;
++
++ ret_fraction_log2(val, val2);
++ return IIO_VAL_INT_PLUS_NANO;
++
++ /* the full scale units : -1.0 to 1-LSB (0x7FFFFF)
++ * As an example, if 230V-peak at the input to the voltage
++ * divider gives 250mV-peak at the chip input, one would get a
++ * full scale register reading of 1 - LSB (0x7FFFFF) for
++ * instaneous voltage.
++ * Similarly, if 30Apk at the sensor input provides 250mV-peak
++ * to the chip input, a full scale register value of 1 - LSB
++ * (0x7FFFFF) for instanteous current would correspond to
++ * 30 amps.
++ * Full scale watts correspond to the result of full scale
++ * current and voltage so, in this example, full scale watts
++ * is 230 x 30 or 6900 watts.
++ */
++
++ case IIO_CHAN_INFO_SCALE:
++ switch (chan->type) {
++ case IIO_CURRENT:
++ *val = 250; /* unit mV */
++ return IIO_VAL_INT;
++
++ case IIO_VOLTAGE:
++ *val = 250; /* unit: mV */
++ return IIO_VAL_INT;
++
++ case IIO_POWER:
++ *val = 250*250; /* uV */
++ return IIO_VAL_INT;
++
++ default:
++ return -EINVAL;
++ }
++
++ }
++ return -EINVAL;
++}
++
++/**
++ * max78m6610_lmu_write_raw
++ *
++ * @param indio_dev: iio_dev pointer
++ * @param chan: pointer to iio channel spec struct
++ * @param val: input value pointer
++ * @param val2: input value 2 ponter
++ * @parma m: write mask indicating IIO info type
++ * @return: status indicating success (zero) or fail (non-zero)
++ *
++ * This function will be invoked on a request to write a value to the device.
++ * Write mask specifies an IIO value type, val and val2 contain the integer and
++ * fractional elements of the floating point input value (INT+NANO).
++ */
++static int max78m6610_lmu_write_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int val,
++ int val2,
++ long m)
++{
++ int ret;
++ u32 regval;
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ ret = -EBUSY;
++ goto exit_unlock;
++ }
++
++ switch (m) {
++
++ case IIO_CHAN_INFO_RAW:
++ ret = intplusnano_to_regval(val, val2,
++ chan->scan_type.shift, &regval);
++ if (ret)
++ goto exit_unlock;
++
++ ret = __max78m6610_lmu_spi_reg_write(st, chan->address, regval);
++ break;
++
++ default:
++ pr_err("Invalid channel selected for writing\n");
++ ret = -EINVAL;
++ goto exit_unlock;
++ }
++
++exit_unlock:
++ mutex_unlock(&indio_dev->mlock);
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_write_raw_get_fmt
++ *
++ * @param indio_dev: iio_dev pointer
++ * @param chan: pointer to iio channel spec struct
++ * @param mask: specifies which value to be written
++ * @return: the format specifier for the channel value to be written
++ *
++ * IIO will query the expected format of the input value, and will then
++ * interpret and format it correctly before passing it to
++ * max78m6610_lmu_write_raw(). In all cases, we expect floating point
++ * numbers as input, which IIO will convert into integer and fractional parts
++ */
++static int max78m6610_lmu_write_raw_get_fmt(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ long mask)
++{
++ return IIO_VAL_INT_PLUS_NANO;
++}
++
++
++/**
++ * max78m6610_lmu_reg_access
++ *
++ * @param indio_dev: iio_dev pointer
++ * @param reg: register address
++ * @param writeval: register value to write (ignored if readval is set)
++ * @parma readval: pointer to return register read result (set NULL for write)
++ * @return: status indicating success (zero) or fail (non-zero)
++ *
++ * This function allows direct read/write access MAX78M6610+LMU registers
++ * for debug only
++ */
++static int max78m6610_lmu_reg_access(struct iio_dev *indio_dev,
++ unsigned reg, unsigned writeval,
++ unsigned *readval)
++{
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++ int ret = 0;
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ ret = -EBUSY;
++ goto exit_unlock;
++ }
++
++ if (readval)
++ ret = __max78m6610_lmu_spi_reg_read(st, reg, readval);
++ else
++ ret = __max78m6610_lmu_spi_reg_write(st, reg, writeval);
++
++exit_unlock:
++ mutex_unlock(&indio_dev->mlock);
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_reset
++ *
++ * @param indio_dev: iio_dev pointer
++ *
++ * Executes a reset of the MAX78M6610+LMU by briefly asserting the
++ * hardware reset signal for the device. Volatile register values
++ * will revert to power-on default values.
++ */
++static int max78m6610_lmu_reset(struct iio_dev *indio_dev)
++{
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++ int ret = 0;
++ int gpio = st->reset_gpio;
++
++ struct gpio device_reset_gpio = {
++ gpio,
++ GPIOF_OUT_INIT_HIGH,
++ "max78m6610_lmu_reset"
++ };
++
++ if (gpio < 0) {
++ pr_err("Reset GPIO has not been configured\n");
++ return -ENXIO;
++ }
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ ret = -EBUSY;
++ goto exit_unlock;
++ }
++
++ ret = gpio_request_array(&device_reset_gpio, 1);
++ if (ret) {
++ pr_err("%s: Failed to allocate Device Reset GPIO pin\n",
++ __func__);
++ goto exit_unlock;
++ }
++ gpio_set_value(gpio, 0);
++ msleep(RESET_DELAY_MSEC);
++ gpio_set_value(gpio, 1);
++ msleep(RESET_DELAY_MSEC);
++
++ gpio_free_array(&device_reset_gpio, 1);
++
++exit_unlock:
++ mutex_unlock(&indio_dev->mlock);
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_write_reset
++ *
++ * @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
++ * reset of the MAX78M6610+LMU if an appropriate value is written.
++ * Valid input character values are 1, y and Y
++ */
++static ssize_t max78m6610_lmu_write_reset(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_reset(indio_dev);
++ return ret ? ret : len;
++ }
++ return -1;
++}
++
++/**
++ * max78m6610_lmu_calib_cmd
++ *
++ * @param indio_dev: iio_dev pointer
++ * @param calib_command: 24-bit calibration command value
++ *
++ * Executes a specified calibration command on the MAX78M6610+LMU
++ * The calib_command input value is written directly to the COMMAND
++ * register on the device, to invoke a selected automatic calibration
++ * routine. The driver waits until the calibration completes, and then
++ * checks the status (depending on the specific command)
++ */
++static int max78m6610_lmu_calib_cmd(struct iio_dev *indio_dev,
++ u32 calib_command)
++{
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++ u32 samples, calcycs;
++ unsigned delay_ms;
++ int max_retries = 5;
++ int ret = 0;
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ ret = -EBUSY;
++ goto exit_unlock;
++ }
++
++ /* Calculate the delay required for calibration to complete */
++ ret = __max78m6610_lmu_spi_reg_read(st, SAMPLES, &samples);
++ if (ret)
++ goto exit_unlock;
++ ret = __max78m6610_lmu_spi_reg_read(st, CALCYCS, &calcycs);
++ if (ret)
++ goto exit_unlock;
++ delay_ms = (samples * calcycs * SAMPLE_INTERVAL_USEC)/1000;
++
++ ret = __max78m6610_lmu_spi_reg_write(st, COMMAND, calib_command);
++ if (ret)
++ goto exit_unlock;
++
++ do {
++ /* Wait for the calibration to complete */
++ mdelay(delay_ms);
++
++ ret = __max78m6610_lmu_spi_reg_read(st, COMMAND,
++ &calib_command);
++ if (ret)
++ goto exit_unlock;
++ } while ((calib_command & 0xFF0000) && (max_retries--));
++
++ if (max_retries <= 0) {
++ pr_err("Timed out waiting for calibration to complete\n");
++ ret = -EIO;
++ goto exit_unlock;
++ }
++
++ /* Gain calibration commands (bit 9 unset) can be checked for failure */
++ if ((!(calib_command & 0x000200)) && (calib_command & 0x007800)) {
++ pr_err("Calibration failed: COMMAND=0x%06X\n", calib_command);
++ ret = -EFAULT;
++ }
++
++exit_unlock:
++ mutex_unlock(&indio_dev->mlock);
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_write_calib
++ *
++ * @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
++ * calibration command on the MAX78M6610+LMU if an appropriate value is written.
++ * Valid input character values are 1, y and Y.
++ * The handler is re-used for multiple calibration commands, so the command
++ * value is passed transparently via the attribute address field
++ */
++static ssize_t max78m6610_lmu_write_calib(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t len)
++{
++ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
++ 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_calib_cmd(indio_dev, this_attr->address);
++ return ret ? ret : len;
++ }
++ return -1;
++}
++
++/**
++ * max78m6610_lmu_flash_save_cmd
++ *
++ * @param indio_dev: iio_dev pointer
++ *
++ * Executes a flash-save command on the MAX78M6610+LMU.
++ * This saves all current volatile register values to flash on the device,
++ * making them persistent across device resets or power cycles.
++ */
++static int max78m6610_lmu_flash_save_cmd(struct iio_dev *indio_dev)
++{
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++ int ret = 0;
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ ret = -EBUSY;
++ goto exit_unlock;
++ }
++
++ ret = __max78m6610_lmu_spi_reg_write(st, COMMAND, FLASHSAVE_CMD);
++
++exit_unlock:
++ mutex_unlock(&indio_dev->mlock);
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_write_flash
++ *
++ * @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
++ * flash-save command 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_flash(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_flash_save_cmd(indio_dev);
++ return ret ? ret : len;
++ }
++ return -1;
++}
++
++/**
++ * max78m6610_lmu_flash_save_cmd
++ *
++ * @param indio_dev: iio_dev pointer
++ *
++ * Executes a read of the STATUS register on the MAX78M6610+LMU.
++ * Event status bits are checked, and event notifications are raised for
++ * user-space applications if any events are asserted. Event status bits are
++ * sticky and are cleared by setting the corresponding bit in the STATUS_RESET
++ * register to allow further occurances of the same event to be detected
++ */
++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();
++
++ mutex_lock(&indio_dev->mlock);
++ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
++ ret = -EBUSY;
++ goto exit_unlock;
++ }
++
++ ret = __max78m6610_lmu_spi_reg_read(st, STATUS, &status);
++ if (ret) {
++ pr_err("Failed to read STATUS register\n");
++ goto exit_unlock;
++ }
++
++ status &= ~STATUS_MASK_IGNORE;
++
++ /* Nothing more to do if no interesting status bits are set */
++ if (!status)
++ goto exit_unlock;
++
++ /* 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) {
++ iio_push_event(indio_dev,
++ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
++ IIO_EV_TYPE_MAG,
++ IIO_EV_DIR_FALLING),
++ timestamp_ns);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++ if (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);
++ }
++
++ ret = __max78m6610_lmu_spi_reg_write(st, STATUS_RESET,
++ status & STATUS_MASK_STICKY);
++ if (ret) {
++ pr_err("Failed to write STATUS_RESET register\n");
++ goto exit_unlock;
++ }
++
++exit_unlock:
++ 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
++ *
++ * @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 is a generic handler to write integer values to any integer registers
++ * which are exposed as device sysfs attributes on the user interface.
++ * The attribute address field specifies which register to write.
++ */
++
++static IIO_DEVICE_ATTR(do_reset, S_IWUSR, NULL,
++ max78m6610_lmu_write_reset, 0);
++static IIO_DEVICE_ATTR(do_voltage0_gain_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S0_GAIN);
++static IIO_DEVICE_ATTR(do_current0_gain_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S1_GAIN);
++static IIO_DEVICE_ATTR(do_voltage1_gain_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S2_GAIN);
++static IIO_DEVICE_ATTR(do_current1_gain_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S3_GAIN);
++static IIO_DEVICE_ATTR(do_voltage0_offset_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S0_OFFS);
++static IIO_DEVICE_ATTR(do_current0_offset_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S1_OFFS);
++static IIO_DEVICE_ATTR(do_voltage1_offset_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S2_OFFS);
++static IIO_DEVICE_ATTR(do_current1_offset_calib, S_IWUSR, NULL,
++ max78m6610_lmu_write_calib, CALCMD_S3_OFFS);
++static IIO_DEVICE_ATTR(do_save_to_flash, S_IWUSR, NULL,
++ max78m6610_lmu_write_flash, 0);
++
++static struct attribute *max78m6610_lmu_attributes[] = {
++ &iio_dev_attr_do_reset.dev_attr.attr,
++ &iio_dev_attr_do_voltage0_gain_calib.dev_attr.attr,
++ &iio_dev_attr_do_current0_gain_calib.dev_attr.attr,
++ &iio_dev_attr_do_voltage1_gain_calib.dev_attr.attr,
++ &iio_dev_attr_do_current1_gain_calib.dev_attr.attr,
++ &iio_dev_attr_do_voltage0_offset_calib.dev_attr.attr,
++ &iio_dev_attr_do_current0_offset_calib.dev_attr.attr,
++ &iio_dev_attr_do_voltage1_offset_calib.dev_attr.attr,
++ &iio_dev_attr_do_current1_offset_calib.dev_attr.attr,
++ &iio_dev_attr_do_save_to_flash.dev_attr.attr,
++ NULL,
++};
++
++static const struct attribute_group max78m6610_lmu_attribute_group = {
++ .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);
++
++/* 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,
++ NULL,
++};
++
++static struct attribute_group max78m6610_lmu_event_attribute_group = {
++ .attrs = max78m6610_lmu_event_attributes,
++};
++
++
++/* Driver specific iio info structure */
++static const struct iio_info max78m6610_lmu_info = {
++ .read_raw = max78m6610_lmu_read_raw,
++ .write_raw = max78m6610_lmu_write_raw,
++ .write_raw_get_fmt = max78m6610_lmu_write_raw_get_fmt,
++ .debugfs_reg_access = max78m6610_lmu_reg_access,
++ .update_scan_mode = max78m6610_lmu_update_scan_mode,
++ .event_attrs = &max78m6610_lmu_event_attribute_group,
++ .attrs = &max78m6610_lmu_attribute_group,
++ .driver_module = THIS_MODULE,
++};
++
++/**
++ * max78m6610_lmu_open
++ *
++ * @param inode: inode descriptor associated with char device
++ * @param filp: file object pointer
++ * @return 0 on success, non-zero errno otherwise
++ *
++ * This handles an open syscall on the character device node
++ */
++static int
++max78m6610_lmu_open(struct inode *inode, struct file *filp)
++{
++ struct max78m6610_lmu_state *st;
++ int ret = 0;
++
++ st = container_of(inode->i_cdev,
++ struct max78m6610_lmu_state,
++ cdev);
++ filp->private_data = st;
++
++ if (!st->bbuffer) {
++ st->bbuffer = kmalloc(SPI_BBUFFER_LEN, GFP_KERNEL);
++ if (!st->bbuffer) {
++ dev_dbg(&st->spi->dev, "open/ENOMEM\n");
++ ret = -ENOMEM;
++ }
++ }
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_release
++ *
++ * @param inode: inode descriptor associated with char device
++ * @param filp: file object pointer
++ * @return 0 on success, non-zero errno otherwise
++ *
++ * This handles a close syscall on the character device node
++ */
++static int
++max78m6610_lmu_release(struct inode *inode, struct file *filp)
++{
++ struct max78m6610_lmu_state *st =
++ (struct max78m6610_lmu_state *)filp->private_data;
++
++ kfree(st->bbuffer);
++ st->bbuffer = NULL;
++
++ return 0;
++}
++
++/**
++ * spidev_message
++ *
++ * @param st: driver state information
++ * @param u_xfers: spi transfer descriptor array
++ * @param n_xfers: number of spi transfer descriptors
++ * @return 0 on success, non-zero errno otherwise
++ *
++ * Translates a set of user-space SPI transfer requests to kernel-space
++ * equivalent, using bounce-buffers for the data, and invokes spi_sync()
++ * to execute the bi-directional SPI transfers
++ *
++ * The implementation below was borrowed directly from the spidev kernel driver
++ * with minor modifications to fit it in here
++ */
++static int spidev_message(struct max78m6610_lmu_state *st,
++ struct spi_ioc_transfer *u_xfers,
++ unsigned n_xfers)
++{
++ struct spi_message msg;
++ struct spi_transfer *k_xfers;
++ struct spi_transfer *k_tmp;
++ struct spi_ioc_transfer *u_tmp;
++ unsigned n, total;
++ u8 *buf;
++ int status = -EFAULT;
++
++ spi_message_init(&msg);
++ k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
++ if (k_xfers == NULL)
++ return -ENOMEM;
++
++ /* Construct spi_message, copying any tx data to bounce buffer.
++ * We walk the array of user-provided transfers, using each one
++ * to initialize a kernel version of the same transfer.
++ */
++ buf = st->bbuffer;
++ total = 0;
++ for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
++ n;
++ n--, k_tmp++, u_tmp++) {
++ k_tmp->len = u_tmp->len;
++
++ total += k_tmp->len;
++ if (total > SPI_BBUFFER_LEN) {
++ status = -EMSGSIZE;
++ goto done;
++ }
++
++ if (u_tmp->rx_buf) {
++ k_tmp->rx_buf = buf;
++ if (!access_ok(VERIFY_WRITE, (u8 __user *)
++ (uintptr_t) u_tmp->rx_buf,
++ u_tmp->len))
++ goto done;
++ }
++ if (u_tmp->tx_buf) {
++ k_tmp->tx_buf = buf;
++ if (copy_from_user(buf, (const u8 __user *)
++ (uintptr_t) u_tmp->tx_buf,
++ u_tmp->len))
++ goto done;
++ }
++ buf += k_tmp->len;
++
++ k_tmp->cs_change = !!u_tmp->cs_change;
++ k_tmp->bits_per_word = u_tmp->bits_per_word;
++ k_tmp->delay_usecs = u_tmp->delay_usecs;
++ k_tmp->speed_hz = u_tmp->speed_hz;
++#ifdef VERBOSE
++ dev_dbg(&st->spi->dev,
++ " xfer len %zd %s%s%s%dbits %u usec %uHz\n",
++ u_tmp->len,
++ u_tmp->rx_buf ? "rx " : "",
++ u_tmp->tx_buf ? "tx " : "",
++ u_tmp->cs_change ? "cs " : "",
++ u_tmp->bits_per_word ? : st->spi->bits_per_word,
++ u_tmp->delay_usecs,
++ u_tmp->speed_hz ? : st->spi->max_speed_hz);
++#endif
++ spi_message_add_tail(k_tmp, &msg);
++ }
++
++ status = spi_sync(st->spi, &msg);
++ if (status < 0)
++ goto done;
++
++ /* copy any rx data out of bounce buffer */
++ buf = st->bbuffer;
++ for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
++ if (u_tmp->rx_buf) {
++ if (__copy_to_user((u8 __user *)
++ (uintptr_t) u_tmp->rx_buf, buf,
++ u_tmp->len)) {
++ status = -EFAULT;
++ goto done;
++ }
++ }
++ buf += u_tmp->len;
++ }
++ status = total;
++
++done:
++ kfree(k_xfers);
++ return status;
++}
++
++/**
++ * max78m6610_lmu_ioctl
++ *
++ * @param filp: file object pointer
++ * @param cmd: ioctl command
++ * @param arg: optional data argument
++ * @return 0 on success, non-zero errno otherwise
++ *
++ * This handles an ioctl syscall on the character device node. This handler
++ * supports only the SPI_IOC_MESSAGE ioctl command defined in spidev.h
++ * The implementation below was borrowed from the spidev driver, with some minor
++ * modifications to remove support for other ioctl commands not needed here
++ */
++static long
++max78m6610_lmu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
++{
++ struct max78m6610_lmu_state *st = filp->private_data;
++ struct iio_dev *indio_dev = spi_get_drvdata(st->spi);
++ u32 tmp;
++ unsigned n_ioc;
++ struct spi_ioc_transfer *ioc;
++ int ret = 0;
++
++ /* Check type and command number */
++ if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
++ return -ENOTTY;
++
++ /* Check access direction once here; don't repeat below.
++ * IOC_DIR is from the user perspective, while access_ok is
++ * from the kernel perspective; so they look reversed.
++ */
++ if (_IOC_DIR(cmd) & _IOC_READ)
++ ret = !access_ok(VERIFY_WRITE,
++ (void __user *)arg, _IOC_SIZE(cmd));
++ if (ret == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
++ ret = !access_ok(VERIFY_READ,
++ (void __user *)arg, _IOC_SIZE(cmd));
++ if (ret)
++ return -EFAULT;
++
++ ret = mutex_lock_interruptible(&indio_dev->mlock);
++ if (ret)
++ return ret;
++
++ /* segmented and/or full-duplex I/O request */
++ if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
++ || _IOC_DIR(cmd) != _IOC_WRITE) {
++ ret = -ENOTTY;
++ goto exit;
++ }
++
++ tmp = _IOC_SIZE(cmd);
++ if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
++ ret = -EINVAL;
++ goto exit;
++ }
++ n_ioc = tmp / sizeof(struct spi_ioc_transfer);
++ if (n_ioc == 0)
++ goto exit;
++
++ /* copy into scratch area */
++ ioc = kmalloc(tmp, GFP_KERNEL);
++ if (!ioc) {
++ ret = -ENOMEM;
++ goto exit;
++ }
++ if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
++ kfree(ioc);
++ ret = -EFAULT;
++ goto exit;
++ }
++
++ /* translate to spi_message, execute */
++ ret = spidev_message(st, ioc, n_ioc);
++ kfree(ioc);
++
++exit:
++ mutex_unlock(&indio_dev->mlock);
++
++ return ret;
++}
++
++static const struct file_operations max78m6610_lmu_fops = {
++ .owner = THIS_MODULE,
++ .open = max78m6610_lmu_open,
++ .release = max78m6610_lmu_release,
++ .unlocked_ioctl = max78m6610_lmu_ioctl,
++};
++
++/**
++ * max78m6610_lmu_chrdev_init
++ *
++ * @param st: driver state information
++ * @return 0 on success, non-zero errno otherwise
++ *
++ * Creates a character device to implement a subset of the spidev user-interface
++ * API, namely full-duplex SPI transfers via the ioctl() interface.
++ * The intention is to provide user-space applications with direct access to the
++ * underlying SPI device if required. The user-space application is, in this
++ * mode of operation, responsible for directly constructing the SPI messages
++ * required by the MAX78M6610 and those messages are passed transparently
++ * through this driver. This is needed, for example, to facilitate binary-only
++ * firmware update applications, but may also be used by user-space applications
++ * to access any device registers which have not been exposed by this driver.
++ *
++ * The device node created will appear in the filesystem as /dev/max78m6610_lmu
++ */
++static int
++max78m6610_lmu_chrdev_init(struct max78m6610_lmu_state *st)
++{
++ int ret;
++ struct device *dev;
++
++ ret = alloc_chrdev_region(&st->cdev_no, 0, 1,
++ "max78m6610_lmu");
++ if (ret) {
++ pr_err("Failed to alloc chrdev: %d", ret);
++ return ret;
++ }
++
++ cdev_init(&st->cdev, &max78m6610_lmu_fops);
++
++ ret = cdev_add(&st->cdev, st->cdev_no, 1);
++ if (ret) {
++ pr_err("Failed to add cdev: %d", ret);
++ unregister_chrdev_region(st->cdev_no, 1);
++ return ret;
++ }
++
++ st->cl = class_create(THIS_MODULE, "char");
++ if (IS_ERR(st->cl)) {
++ pr_err("Failed to create device class: %ld",
++ PTR_ERR(st->cl));
++ cdev_del(&st->cdev);
++ unregister_chrdev_region(st->cdev_no, 1);
++ return PTR_ERR(st->cl);
++ }
++
++ dev = device_create(st->cl, NULL, st->cdev_no, NULL,
++ "max78m6610_lmu");
++ if (IS_ERR(dev)) {
++ pr_err("Failed to create device: %ld",
++ PTR_ERR(st->cl));
++ class_destroy(st->cl);
++ cdev_del(&st->cdev);
++ unregister_chrdev_region(st->cdev_no, 1);
++ return PTR_ERR(dev);
++ }
++
++ return 0;
++}
++
++/**
++ * max78m6610_lmu_chrdev_remove
++ *
++ * @param st: driver state information
++ * @return 0 on success, non-zero errno otherwise
++ *
++ * Remove the character device created by max78m6610_lmu_chrdev_init()
++ */
++static int
++max78m6610_lmu_chrdev_remove(struct max78m6610_lmu_state *st)
++{
++ device_destroy(st->cl, st->cdev_no);
++ class_destroy(st->cl);
++ cdev_del(&st->cdev);
++ unregister_chrdev_region(st->cdev_no, 1);
++
++ return 0;
++}
++
++/**
++ * max78m6610_lmu_probe
++ *
++ * @param spi: spi device pointer
++ * @return: return 0 or standard errorids if failure
++ *
++ * device driver probe funciton for iio_dev struct initialisation.
++ */
++static int max78m6610_lmu_probe(struct spi_device *spi)
++{
++ struct max78m6610_lmu_state *st;
++ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
++ struct max78m6610_lmu_platform_data *pdata = spi->dev.platform_data;
++ int ret;
++
++ if (indio_dev == NULL)
++ return -ENOMEM;
++ st = iio_priv(indio_dev);
++
++ spi_set_drvdata(spi, indio_dev);
++ st->spi = spi;
++
++ if (pdata)
++ st->reset_gpio = pdata->reset_gpio;
++ else
++ st->reset_gpio = -1;
++
++ indio_dev->name = spi_get_device_id(spi)->name;
++ indio_dev->dev.parent = &spi->dev;
++ indio_dev->modes = INDIO_DIRECT_MODE;
++ indio_dev->channels = max78m6610_lmu_channels;
++ indio_dev->num_channels = ARRAY_SIZE(max78m6610_lmu_channels);
++ indio_dev->info = &max78m6610_lmu_info;
++
++ /* Setup default message */
++ st->scan_single_xfer.tx_buf = &st->tx_buf[0];
++ st->scan_single_xfer.rx_buf = &st->rx_buf[0];
++ st->scan_single_xfer.len = SPI_MSG_LEN;
++
++ 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,
++ &max78m6610_lmu_trigger_handler, NULL);
++ if (ret) {
++ pr_err("triger buffer setup failed !\n");
++ goto error_free;
++ }
++
++ pr_debug("%s: alloc dev id: %d\n", __func__, indio_dev->id);
++ ret = iio_device_register(indio_dev);
++ if (ret)
++ goto error_cleanup_ring;
++
++ ret = max78m6610_lmu_chrdev_init(st);
++ if (ret)
++ goto error_cleanup_ring;
++
++ return 0;
++
++error_cleanup_ring:
++ iio_triggered_buffer_cleanup(indio_dev);
++error_free:
++ iio_device_free(indio_dev);
++
++ return ret;
++}
++
++/**
++ * max78m6610_lmu_remove
++ *
++ * @param spi: spi device pointer
++ * @return: return 0
++ *
++ * iio device unregister & cleanup
++ */
++static int max78m6610_lmu_remove(struct spi_device *spi)
++{
++ struct iio_dev *indio_dev = spi_get_drvdata(spi);
++ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
++
++ max78m6610_lmu_chrdev_remove(st);
++ iio_device_unregister(indio_dev);
++ iio_triggered_buffer_cleanup(indio_dev);
++ iio_device_free(indio_dev);
++
++ return 0;
++}
++
++static const struct spi_device_id max78m6610_lmu_id[] = {
++ {"max78m6610_lmu", 0},
++ {}
++};
++MODULE_DEVICE_TABLE(spi, max78m6610_lmu_id);
++
++static struct spi_driver max78m6610_lmu_driver = {
++ .driver = {
++ .name = "max78m6610_lmu",
++ .owner = THIS_MODULE,
++ },
++ .probe = max78m6610_lmu_probe,
++ .remove = max78m6610_lmu_remove,
++ .id_table = max78m6610_lmu_id,
++};
++
++/**
++ * max78m6610_lmu_init
++ *
++ * device driver module init
++ */
++static __init int max78m6610_lmu_init(void)
++{
++ int ret;
++
++ ret = spi_register_driver(&max78m6610_lmu_driver);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++module_init(max78m6610_lmu_init);
++
++/**
++ * max78m6610_lmu_exit
++ *
++ * device driver module exit
++ */
++static __exit void max78m6610_lmu_exit(void)
++{
++ spi_unregister_driver(&max78m6610_lmu_driver);
++}
++module_exit(max78m6610_lmu_exit);
++
++
++MODULE_AUTHOR("Kai Ji <kai.ji@emutex.com>");
++MODULE_DESCRIPTION("Maxim 78M6610+LMU eADC");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig
+index 7d32075..e9e837d 100644
+--- a/drivers/staging/iio/trigger/Kconfig
++++ b/drivers/staging/iio/trigger/Kconfig
+@@ -29,6 +29,17 @@ config IIO_SYSFS_TRIGGER
+
+ To compile this driver as a module, choose M here: the
+ module will be called iio-trig-sysfs.
++
++config IIO_HRTIMER_TRIGGER
++ tristate "HRTIMER trigger"
++ #depends on HRTIMER
++ select IRQ_WORK
++ help
++ Provides support for using HRTIMER entries as IIO triggers.
++ If unsure, say N (but it's safe to say "Y").
++
++ To compile this driver as a module, choose M here: the
++ module will be called iio-trig-hrtimer.
+
+ config IIO_BFIN_TMR_TRIGGER
+ tristate "Blackfin TIMER trigger"
+diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile
+index b088b57..ad2f595 100644
+--- a/drivers/staging/iio/trigger/Makefile
++++ b/drivers/staging/iio/trigger/Makefile
+@@ -5,4 +5,5 @@
+ obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o
+ obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o
+ obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
++obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
+ obj-$(CONFIG_IIO_BFIN_TMR_TRIGGER) += iio-trig-bfin-timer.o
+diff --git a/drivers/staging/iio/trigger/iio-trig-hrtimer.c b/drivers/staging/iio/trigger/iio-trig-hrtimer.c
+new file mode 100644
+index 0000000..5dc30e5
+--- /dev/null
++++ b/drivers/staging/iio/trigger/iio-trig-hrtimer.c
+@@ -0,0 +1,288 @@
++/*
++ * Industrial I/O - hrtimer trigger support
++ *
++ * Copyright 2013 STMicroelectronics Inc.
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published by
++ * the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/hrtimer.h>
++#include <linux/ktime.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++
++#include <linux/iio/iio.h>
++#include <linux/iio/trigger.h>
++
++struct iio_hrtimer_trigger_data {
++ struct iio_trigger *trig;
++ struct hrtimer timer;
++ struct list_head l;
++ ktime_t period;
++ u16 freq;
++ int id;
++};
++
++static LIST_HEAD(iio_hrtimer_trigger_list);
++static DEFINE_MUTEX(iio_hrtimer_trigger_list_mut);
++
++static int iio_hrtimer_trigger_probe(int id);
++static int iio_hrtimer_trigger_remove(int id);
++
++static ssize_t iio_sysfs_hrtimer_trig_add(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ int ret;
++ unsigned long input;
++
++ ret = kstrtoul(buf, 10, &input);
++ if (ret)
++ return ret;
++
++ ret = iio_hrtimer_trigger_probe(input);
++ if (ret)
++ return ret;
++
++ return len;
++}
++static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_hrtimer_trig_add);
++
++static ssize_t iio_sysfs_hrtimer_trig_remove(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ int ret;
++ unsigned long input;
++
++ ret = kstrtoul(buf, 10, &input);
++ if (ret)
++ return ret;
++
++ ret = iio_hrtimer_trigger_remove(input);
++ if (ret)
++ return ret;
++
++ return len;
++}
++static DEVICE_ATTR(remove_trigger, S_IWUSR,
++ NULL, &iio_sysfs_hrtimer_trig_remove);
++
++static struct attribute *iio_hrtimer_trig_attrs[] = {
++ &dev_attr_add_trigger.attr,
++ &dev_attr_remove_trigger.attr,
++ NULL,
++};
++
++static const struct attribute_group iio_hrtimer_trig_group = {
++ .attrs = iio_hrtimer_trig_attrs,
++};
++
++static const struct attribute_group *iio_hrtimer_trig_groups[] = {
++ &iio_hrtimer_trig_group,
++ NULL,
++};
++
++/* Nothing to actually do upon release */
++static void iio_hrtimer_trig_release(struct device *dev)
++{
++}
++
++static struct device iio_hrtimer_trig_dev = {
++ .bus = &iio_bus_type,
++ .groups = iio_hrtimer_trig_groups,
++ .release = &iio_hrtimer_trig_release,
++};
++
++static int iio_hrtimer_trig_set_state(struct iio_trigger *trig, bool state)
++{
++ struct iio_hrtimer_trigger_data *trig_data =
++ dev_get_drvdata(&trig->dev);
++
++ if (trig_data->freq == 0)
++ return -EINVAL;
++
++ if (state)
++ hrtimer_start(&trig_data->timer,
++ trig_data->period, HRTIMER_MODE_REL);
++ else
++ hrtimer_cancel(&trig_data->timer);
++
++ return 0;
++}
++
++static ssize_t iio_hrtimer_trigger_set_freq_value(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t len)
++{
++ int ret;
++ u16 frequency;
++ struct iio_trigger *trig = to_iio_trigger(dev);
++ struct iio_hrtimer_trigger_data *trig_data =
++ dev_get_drvdata(&trig->dev);
++
++ ret = kstrtou16(buf, 10, &frequency);
++ if (ret < 0)
++ return ret;
++
++ if (frequency > NSEC_PER_SEC)
++ return -EINVAL;
++
++ trig_data->freq = frequency;
++
++ if (frequency)
++ trig_data->period =
++ ktime_set(0, NSEC_PER_SEC / trig_data->freq);
++
++ return len;
++}
++
++static ssize_t iio_hrtimer_trigger_get_freq_value(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct iio_trigger *trig = to_iio_trigger(dev);
++ struct iio_hrtimer_trigger_data *trig_data =
++ dev_get_drvdata(&trig->dev);
++
++ return sprintf(buf, "%hu\n", trig_data->freq);
++}
++
++static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO,
++ iio_hrtimer_trigger_get_freq_value,
++ iio_hrtimer_trigger_set_freq_value);
++
++static struct attribute *iio_hrtimer_trigger_attrs[] = {
++ &dev_attr_frequency.attr,
++ NULL,
++};
++
++static const struct attribute_group iio_hrtimer_trigger_attr_group = {
++ .attrs = iio_hrtimer_trigger_attrs,
++};
++
++static const struct attribute_group *iio_hrtimer_trigger_attr_groups[] = {
++ &iio_hrtimer_trigger_attr_group,
++ NULL,
++};
++
++static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
++ .owner = THIS_MODULE,
++ .set_trigger_state = &iio_hrtimer_trig_set_state,
++};
++
++enum hrtimer_restart iio_hrtimer_trigger_func(struct hrtimer *timer)
++{
++ struct iio_hrtimer_trigger_data *trig_data;
++
++ trig_data = container_of(timer, struct iio_hrtimer_trigger_data, timer);
++
++ hrtimer_forward_now(timer, trig_data->period);
++ iio_trigger_poll(trig_data->trig, 0);
++
++ return HRTIMER_RESTART;
++}
++
++static int iio_hrtimer_trigger_probe(int id)
++{
++ int err;
++ bool foundit = false;
++ struct iio_hrtimer_trigger_data *trig_data;
++
++ mutex_lock(&iio_hrtimer_trigger_list_mut);
++ list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
++ if (id == trig_data->id) {
++ foundit = true;
++ break;
++ }
++ }
++ if (foundit) {
++ err = -EINVAL;
++ goto iio_hrtimer_mutex_unlock;
++ }
++
++ trig_data = kmalloc(sizeof(*trig_data), GFP_KERNEL);
++ if (trig_data == NULL) {
++ err = -ENOMEM;
++ goto iio_hrtimer_mutex_unlock;
++ }
++
++ trig_data->id = id;
++ trig_data->trig = iio_trigger_alloc("hrtimer_trig%d", id);
++ if (!trig_data->trig) {
++ err = -ENOMEM;
++ goto iio_hrtimer_free_trig_data;
++ }
++
++ trig_data->trig->dev.groups = iio_hrtimer_trigger_attr_groups;
++ trig_data->trig->ops = &iio_hrtimer_trigger_ops;
++ trig_data->trig->dev.parent = &iio_hrtimer_trig_dev;
++ dev_set_drvdata(&trig_data->trig->dev, trig_data);
++
++ trig_data->freq = 0;
++ hrtimer_init(&trig_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++ trig_data->timer.function = &iio_hrtimer_trigger_func;
++
++ err = iio_trigger_register(trig_data->trig);
++ if (err)
++ goto iio_hrtimer_free_trig_data;
++
++ list_add(&trig_data->l, &iio_hrtimer_trigger_list);
++ __module_get(THIS_MODULE);
++ mutex_unlock(&iio_hrtimer_trigger_list_mut);
++
++ return 0;
++
++iio_hrtimer_free_trig_data:
++ kfree(trig_data);
++iio_hrtimer_mutex_unlock:
++ mutex_unlock(&iio_hrtimer_trigger_list_mut);
++ return err;
++}
++
++static int iio_hrtimer_trigger_remove(int id)
++{
++ bool foundit = false;
++ struct iio_hrtimer_trigger_data *trig_data;
++
++ mutex_lock(&iio_hrtimer_trigger_list_mut);
++ list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
++ if (id == trig_data->id) {
++ foundit = true;
++ break;
++ }
++ }
++ if (!foundit) {
++ mutex_unlock(&iio_hrtimer_trigger_list_mut);
++ return -EINVAL;
++ }
++
++ iio_trigger_unregister(trig_data->trig);
++ iio_trigger_free(trig_data->trig);
++
++ list_del(&trig_data->l);
++ kfree(trig_data);
++ module_put(THIS_MODULE);
++ mutex_unlock(&iio_hrtimer_trigger_list_mut);
++
++ return 0;
++}
++
++static int __init iio_hrtimer_trig_init(void)
++{
++ device_initialize(&iio_hrtimer_trig_dev);
++ dev_set_name(&iio_hrtimer_trig_dev, "iio_hrtimer_trigger");
++ return device_add(&iio_hrtimer_trig_dev);
++}
++module_init(iio_hrtimer_trig_init);
++
++static void __exit iio_hrtimer_trig_exit(void)
++{
++ device_unregister(&iio_hrtimer_trig_dev);
++}
++module_exit(iio_hrtimer_trig_exit);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("Hrtimer trigger for the iio subsystem");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/linux/platform_data/ad7298.h b/include/linux/platform_data/ad7298.h
+index fbf8adf..721ed6f 100644
+--- a/include/linux/platform_data/ad7298.h
++++ b/include/linux/platform_data/ad7298.h
+@@ -9,12 +9,17 @@
+ #ifndef __LINUX_PLATFORM_DATA_AD7298_H__
+ #define __LINUX_PLATFORM_DATA_AD7298_H__
+
++#define AD7298_MAX_CHAN 8
++
+ /**
+ * struct ad7298_platform_data - Platform data for the ad7298 ADC driver
+ * @ext_ref: Whether to use an external reference voltage.
++ * @ext_vin_max: External input voltage range for each voltage input channel
++ * (set to non-zero if platform uses external voltage dividers)
+ **/
+ struct ad7298_platform_data {
+ bool ext_ref;
++ u16 ext_vin_max[AD7298_MAX_CHAN];
+ };
+
+ #endif /* IIO_ADC_AD7298_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
+--- /dev/null
++++ b/include/linux/platform_data/max78m6610_lmu.h
+@@ -0,0 +1,34 @@
++/*
++ * 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.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++#ifndef __LINUX_PLATFORM_DATA_MAX78M6610_LMU_H__
++#define __LINUX_PLATFORM_DATA_MAX78M6610_LMU_H__
++
++/**
++ * struct max78m6610_lmu_platform_data - Platform data for the max78m6610_lmu
++ * ADC driver
++ * @reset_gpio: GPIO pin number reserved for MAX78M6610+LMU device reset
++ **/
++struct max78m6610_lmu_platform_data {
++ int reset_gpio;
++};
++
++#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
new file mode 100644
index 0000000..3d493cb
--- /dev/null
+++ b/recipes-kernel/linux/files/0021-Quark-SPI-flash-quark.patch
@@ -0,0 +1,41 @@
+From xxxx Mon Sep 17 00:00:00 2001
+From: Bryan O'Donoghue <bryan.odonoghue@intel.com>
+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 +--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
+index 46dcb54..4844920 100644
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -159,6 +159,11 @@ config MTD_MTDRAM
+ provide storage. You probably want to say 'N' unless you're
+ testing stuff.
+
++config MTD_MTD_QRK_ROM
++ bool "Simple R/O drive for SPI flash in Quark x86 legacy block"
++ help
++ Driver to enable reading directly from legacy block SPI /sketch part
++
+ config MTDRAM_TOTAL_SIZE
+ int "MTDRAM device size in KiB"
+ depends on MTD_MTDRAM
+diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
+index 395733a..4c8e399 100644
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -20,5 +20,4 @@ obj-$(CONFIG_MTD_M25P80) += m25p80.o
+ obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
+ obj-$(CONFIG_MTD_SST25L) += sst25l.o
+ obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
+-
+-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/clanton-standard.scc b/recipes-kernel/linux/files/clanton-standard.scc
index 18ef1e5..6ca5944 100644
--- a/recipes-kernel/linux/files/clanton-standard.scc
+++ b/recipes-kernel/linux/files/clanton-standard.scc
@@ -2,7 +2,7 @@ define KMACHINE clanton
define KTYPE standard
define KARCH i386
-kconf hardware clanton.cfg
+kconf hardware quark.cfg
include features/latencytop.scc
include features/lttng.scc
diff --git a/recipes-kernel/linux/files/clanton.patch b/recipes-kernel/linux/files/clanton.patch
deleted file mode 100644
index ed2d1fb..0000000
--- a/recipes-kernel/linux/files/clanton.patch
+++ /dev/null
@@ -1,33493 +0,0 @@
-diff --git a/.gitignore b/.gitignore
-index 3b8b9b3..3557999 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -64,11 +64,11 @@ include/generated
- arch/*/include/generated
-
- # stgit generated dirs
--patches-*
-+#patches-*
-
- # quilt's files
--patches
--series
-+#patches
-+#series
-
- # cscope files
- cscope.*
-diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm
-new file mode 100644
-index 0000000..c479d77
---- /dev/null
-+++ b/Documentation/ABI/testing/sysfs-class-pwm
-@@ -0,0 +1,79 @@
-+What: /sys/class/pwm/
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ The pwm/ class sub-directory belongs to the Generic PWM
-+ Framework and provides a sysfs interface for using PWM
-+ channels.
-+
-+What: /sys/class/pwm/pwmchipN/
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ A /sys/class/pwm/pwmchipN directory is created for each
-+ probed PWM controller/chip where N is the base of the
-+ PWM chip.
-+
-+What: /sys/class/pwm/pwmchipN/npwm
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ The number of PWM channels supported by the PWM chip.
-+
-+What: /sys/class/pwm/pwmchipN/export
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ Exports a PWM channel from the PWM chip for sysfs control.
-+ Value is between 0 and /sys/class/pwm/pwmchipN/npwm - 1.
-+
-+What: /sys/class/pwm/pwmchipN/unexport
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ Unexports a PWM channel.
-+
-+What: /sys/class/pwm/pwmchipN/pwmX
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ A /sys/class/pwm/pwmchipN/pwmX directory is created for
-+ each exported PWM channel where X is the exported PWM
-+ channel number.
-+
-+What: /sys/class/pwm/pwmchipN/pwmX/period
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ Sets the PWM signal period in nanoseconds.
-+
-+What: /sys/class/pwm/pwmchipN/pwmX/duty_cycle
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ Sets the PWM signal duty cycle in nanoseconds.
-+
-+What: /sys/class/pwm/pwmchipN/pwmX/polarity
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ Sets the output polarity of the PWM signal to "normal" or
-+ "inversed".
-+
-+What: /sys/class/pwm/pwmchipN/pwmX/enable
-+Date: May 2013
-+KernelVersion: 3.11
-+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
-+Description:
-+ Enable/disable the PWM signal.
-+ 0 is disabled
-+ 1 is enabled
-diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
-index 7d2b4c9..1039b68 100644
---- a/Documentation/pwm.txt
-+++ b/Documentation/pwm.txt
-@@ -45,6 +45,43 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
-
- To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
-
-+Using PWMs with the sysfs interface
-+-----------------------------------
-+
-+If CONFIG_SYSFS is enabled in your kernel configuration a simple sysfs
-+interface is provided to use the PWMs from userspace. It is exposed at
-+/sys/class/pwm/. Each probed PWM controller/chip will be exported as
-+pwmchipN, where N is the base of the PWM chip. Inside the directory you
-+will find:
-+
-+npwm - The number of PWM channels this chip supports (read-only).
-+
-+export - Exports a PWM channel for use with sysfs (write-only).
-+
-+unexport - Unexports a PWM channel from sysfs (write-only).
-+
-+The PWM channels are numbered using a per-chip index from 0 to npwm-1.
-+
-+When a PWM channel is exported a pwmX directory will be created in the
-+pwmchipN directory it is associated with, where X is the number of the
-+channel that was exported. The following properties will then be available:
-+
-+period - The total period of the PWM signal (read/write).
-+ Value is in nanoseconds and is the sum of the active and inactive
-+ time of the PWM.
-+
-+duty_cycle - The active time of the PWM signal (read/write).
-+ Value is in nanoseconds and must be less than the period.
-+
-+polarity - Changes the polarity of the PWM signal (read/write).
-+ Writes to this property only work if the PWM chip supports changing
-+ the polarity. The polarity can only be changed if the PWM is not
-+ enabled. Value is the string "normal" or "inversed".
-+
-+enable - Enable/disable the PWM signal (read/write).
-+ 0 - disabled
-+ 1 - enabled
-+
- Implementing a PWM driver
- -------------------------
-
-diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf
-index f0ffc27..e56f074 100644
---- a/Documentation/usb/linux-cdc-acm.inf
-+++ b/Documentation/usb/linux-cdc-acm.inf
-@@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys
- [SourceDisksFiles]
- [SourceDisksNames]
- [DeviceList]
--%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00
-+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE
-
- [DeviceList.NTamd64]
--%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00
-+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE
-
-
- ;------------------------------------------------------------------------------
-diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
-index 0694d09..2c881ac 100644
---- a/arch/x86/Kconfig
-+++ b/arch/x86/Kconfig
-@@ -417,6 +417,15 @@ config X86_INTEL_CE
- This option compiles in support for the CE4100 SOC for settop
- boxes and media devices.
-
-+config INTEL_QUARK_X1000_SOC
-+ bool "Intel Quark X1000 SOC support"
-+ depends on M586TSC
-+ select ARCH_REQUIRE_GPIOLIB
-+ select I2C
-+ ---help---
-+ Quark X1000 SOC support . This option enables probing for various
-+ PCI-IDs of several on-chip devices provided by the X1000
-+
- config X86_WANT_INTEL_MID
- bool "Intel MID platform support"
- depends on X86_32
-@@ -500,6 +509,13 @@ config X86_SUPPORTS_MEMORY_FAILURE
- depends on X86_64 || !SPARSEMEM
- select ARCH_SUPPORTS_MEMORY_FAILURE
-
-+menu "Intel Media SOC Gen3 support"
-+
-+config ARCH_GEN3
-+ bool "Enable Intel Media SOC Gen3 support"
-+ default y
-+
-+endmenu
- config X86_VISWS
- bool "SGI 320/540 (Visual Workstation)"
- depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT
-@@ -1524,6 +1540,13 @@ config EFI_STUB
-
- See Documentation/x86/efi-stub.txt for more information.
-
-+config EFI_CAPSULE
-+ tristate "EFI capsule update support"
-+ depends on EFI
-+ ---help---
-+ This kernel feature allows for loading of EFI capsule code
-+ with callbacks into the EDK firmware to execute update
-+
- config SECCOMP
- def_bool y
- prompt "Enable seccomp to safely compute untrusted bytecode"
-diff --git a/arch/x86/include/asm/cln.h b/arch/x86/include/asm/cln.h
-new file mode 100644
-index 0000000..4a5b0e3
---- /dev/null
-+++ b/arch/x86/include/asm/cln.h
-@@ -0,0 +1,85 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+#ifndef _ASM_X86_CLN_H
-+#define _ASM_X86_CLN_H
-+
-+#include <linux/pci.h>
-+#include <linux/msi.h>
-+
-+/**
-+ * cln_pci_pvm_mask
-+ *
-+ * Mask PVM bit on a per function basis. Clanton SC components have but one
-+ * vector each - so we mask for what we need
-+ */
-+static inline void cln_pci_pvm_mask(struct pci_dev * dev)
-+{
-+ struct msi_desc *entry;
-+ int mask_bits = 1;
-+
-+ if(unlikely(dev->msi_enabled == 0))
-+ return;
-+
-+ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
-+
-+ if(unlikely(entry == NULL))
-+ return;
-+
-+ pci_write_config_dword(dev, entry->mask_pos, mask_bits);
-+}
-+
-+/**
-+ * cln_pci_pvm_mask
-+ *
-+ * UnMask PVM bit on a per function basis. Clanton SC components have but one
-+ * vector each - so we unmask for what we need
-+ */
-+static inline void cln_pci_pvm_unmask(struct pci_dev * dev)
-+{
-+ struct msi_desc *entry;
-+ int mask_bits = 0;
-+
-+ if(unlikely(dev->msi_enabled == 0))
-+ return;
-+
-+ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
-+
-+ if(unlikely(entry == NULL))
-+ return;
-+
-+ pci_write_config_dword(dev, entry->mask_pos, mask_bits);
-+}
-+
-+/* Convienence macros */
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+ #define mask_pvm(x) cln_pci_pvm_mask(x)
-+ #define unmask_pvm(x) cln_pci_pvm_unmask(x)
-+#else
-+ #define mask_pvm(x)
-+ #define unmask_pvm(x)
-+#endif
-+
-+/* Serial */
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+ #define SERIAL_PORT_DFNS
-+ #define BASE_BAUD 2764800
-+#endif
-+
-+#endif /* _ASM_X86_CLN_H */
-diff --git a/arch/x86/include/asm/imr.h b/arch/x86/include/asm/imr.h
-new file mode 100644
-index 0000000..2c17eec
---- /dev/null
-+++ b/arch/x86/include/asm/imr.h
-@@ -0,0 +1,22 @@
-+/*
-+ * imr.h: Intel Clanton platform imr setup code
-+ *
-+ * (C) Copyright 2012 Intel Corporation
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License
-+ * as published by the Free Software Foundation; version 2
-+ * of the License.
-+ */
-+#ifndef _ASM_X86_IMR_H
-+#define _ASM_X86_IMR_H
-+
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+ extern int intel_cln_imr_runt_setparams(void);
-+ extern int intel_cln_imr_lockall(void);
-+#else
-+ static void intel_cln_imr_runt_setparams(void){}
-+ static void intel_cln_imr_lockall(void){}
-+#endif
-+
-+#endif /* _ASM_X86_IMR_H */
-diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h
-index 628c801..3965f86 100644
---- a/arch/x86/include/asm/serial.h
-+++ b/arch/x86/include/asm/serial.h
-@@ -1,6 +1,8 @@
- #ifndef _ASM_X86_SERIAL_H
- #define _ASM_X86_SERIAL_H
-
-+#include <asm/cln.h>
-+
- /*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
-@@ -8,7 +10,9 @@
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-+#ifndef BASE_BAUD
- #define BASE_BAUD ( 1843200 / 16 )
-+#endif
-
- /* Standard COM flags (except for COM4, because of the 8514 problem) */
- #ifdef CONFIG_SERIAL_DETECT_IRQ
-@@ -19,11 +23,13 @@
- #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
- #endif
-
-+#ifndef SERIAL_PORT_DFNS
- #define SERIAL_PORT_DFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-+#endif
-
- #endif /* _ASM_X86_SERIAL_H */
-diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
-index fcaabd0..ea7624c 100644
---- a/arch/x86/kernel/cpu/intel.c
-+++ b/arch/x86/kernel/cpu/intel.c
-@@ -143,6 +143,17 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
- setup_clear_cpu_cap(X86_FEATURE_ERMS);
- }
- }
-+
-+ /*
-+ * Quark X1000 PGE is advertised but not implemented. This matters since
-+ * cpu_has_pge is used to determine the type of TLB flushing to do. With
-+ * PGE not actually doing what it says on the tin writes to CR4.PGE do
-+ * nothing when we should be re-writing CR3 like a 486
-+ */
-+ if (c->x86 == 5 && c->x86_model == 9){
-+ printk(KERN_INFO "Disabling PGE capability bit\n");
-+ setup_clear_cpu_cap(X86_FEATURE_PGE);
-+ }
- }
-
- #ifdef CONFIG_X86_32
-diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
-index 8b24289..c963186 100644
---- a/arch/x86/kernel/setup.c
-+++ b/arch/x86/kernel/setup.c
-@@ -761,7 +761,10 @@ void __init setup_arch(char **cmdline_p)
- KERNEL_PGD_PTRS);
-
- load_cr3(swapper_pg_dir);
-- __flush_tlb_all();
-+ if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_model == 9)
-+ __flush_tlb();
-+ else
-+ __flush_tlb_all();
- #else
- printk(KERN_INFO "Command line: %s\n", boot_command_line);
- #endif
-diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
-index 6db1cc4..03a4329 100644
---- a/arch/x86/platform/efi/Makefile
-+++ b/arch/x86/platform/efi/Makefile
-@@ -1,2 +1,3 @@
- obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
--obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
-+obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
-+obj-$(CONFIG_EFI_CAPSULE) += efi_capsule_update.o
-diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
-index d9c1b95..9fd5168 100644
---- a/arch/x86/platform/efi/efi-bgrt.c
-+++ b/arch/x86/platform/efi/efi-bgrt.c
-@@ -24,19 +24,29 @@ struct bmp_header {
- u32 size;
- } __packed;
-
--void efi_bgrt_init(void)
-+bool __init efi_bgrt_probe(void)
- {
- acpi_status status;
-- void __iomem *image;
-- bool ioremapped = false;
-- struct bmp_header bmp_header;
-
- if (acpi_disabled)
-- return;
-+ return false;
-
-+ bgrt_tab = NULL;
- status = acpi_get_table("BGRT", 0,
- (struct acpi_table_header **)&bgrt_tab);
- if (ACPI_FAILURE(status))
-+ return false;
-+
-+ return true;
-+}
-+
-+void __init efi_bgrt_init(void)
-+{
-+ void __iomem *image;
-+ bool ioremapped = false;
-+ struct bmp_header bmp_header;
-+
-+ if (acpi_disabled || bgrt_tab == NULL)
- return;
-
- if (bgrt_tab->header.length < sizeof(*bgrt_tab))
-diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
-index e2cd38f..0e22b5f 100644
---- a/arch/x86/platform/efi/efi.c
-+++ b/arch/x86/platform/efi/efi.c
-@@ -847,6 +847,7 @@ void __init efi_enter_virtual_mode(void)
- u64 end, systab, end_pfn;
- void *p, *va, *new_memmap = NULL;
- int count = 0;
-+ bool bgrt_map;
-
- efi.systab = NULL;
-
-@@ -860,6 +861,11 @@ void __init efi_enter_virtual_mode(void)
- return;
- }
-
-+ /*
-+ * Determine if mapping EFI boot code/data is required for BGRT mapping
-+ */
-+ bgrt_map = efi_bgrt_probe();
-+
- /* Merge contiguous regions of the same type and attribute */
- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
- u64 prev_size;
-@@ -889,9 +895,9 @@ void __init efi_enter_virtual_mode(void)
-
- for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
- md = p;
-- if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
-- md->type != EFI_BOOT_SERVICES_CODE &&
-- md->type != EFI_BOOT_SERVICES_DATA)
-+ if (!((md->attribute & EFI_MEMORY_RUNTIME) || (bgrt_map &&
-+ (md->type == EFI_BOOT_SERVICES_CODE ||
-+ md->type == EFI_BOOT_SERVICES_DATA))))
- continue;
-
- 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..ccd4268
---- /dev/null
-+++ b/arch/x86/platform/efi/efi_capsule_update.c
-@@ -0,0 +1,332 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+#define DEBUG
-+#include <asm/cln.h>
-+#include <linux/errno.h>
-+#include <linux/firmware.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/efi.h>
-+
-+#define DRIVER_NAME "efi_capsule_update"
-+#define PFX "efi-capsupdate: "
-+#define MAX_PATH 256
-+#define MAX_CHUNK PAGE_SIZE
-+#define CSH_HDR_SIZE 0x400
-+
-+typedef struct {
-+ u64 length;
-+ union {
-+ u64 data_block;
-+ u64 continuation_pointer;
-+ };
-+} efi_blk_desc_t;
-+
-+static struct kobject * efi_capsule_kobj;
-+static struct device *dev;
-+static struct list_head sg_list;
-+static char fpath[MAX_PATH];
-+static bool path_set = false;
-+static int csh_jump = CSH_HDR_SIZE; /* Clanton EDK wants CSH jump */
-+
-+/**
-+ * efi_capsule_trigger_update
-+ *
-+ * Trigger the EFI capsule update
-+ */
-+static int efi_capsule_trigger_update(void)
-+{
-+ const struct firmware *fw_entry;
-+ int ret = 0;
-+ u32 nblocks = 0, i = 0, total_size = 0, data_len = 0, offset = 0;
-+ efi_capsule_header_t *chdr = NULL;
-+ efi_blk_desc_t * desc_block = NULL;
-+ //u8 ** data = NULL;
-+ u8 * data = NULL;
-+
-+ if (path_set == false)
-+ return -ENODEV;
-+
-+ ret = request_firmware(&fw_entry, fpath, dev);
-+ if (ret){
-+ pr_err(PFX"unable to load firmware %s\n", fpath);
-+ return ret;
-+ }
-+
-+ /* Determine necessary sizes */
-+ nblocks = (fw_entry->size/MAX_CHUNK) + 2;
-+ total_size = fw_entry->size;
-+
-+ /* Allocate array of descriptor blocks + 1 for terminator */
-+ desc_block = (efi_blk_desc_t*)kzalloc(nblocks * sizeof(efi_blk_desc_t), GFP_KERNEL);
-+ if (desc_block == NULL){
-+ pr_info(PFX"%s failed to allocate %d blocks\n", __func__, nblocks);
-+ ret = -ENOMEM;
-+ goto done_close;
-+ }
-+
-+ pr_info(PFX"File %s size %u descriptor blocks %u\n",
-+ fpath, total_size, nblocks);
-+
-+ /* Read in data */
-+ for (i = 0; i < nblocks && offset < total_size; i++){
-+ /* Determine read len */
-+ data_len = offset < total_size - MAX_CHUNK ?
-+ MAX_CHUNK : total_size - offset;
-+ data = kmalloc(MAX_CHUNK, GFP_KERNEL);
-+ if (data == NULL){
-+ ret = -ENOMEM;
-+ pr_info("Alloc fail %d bytes entry %d\n",
-+ nblocks, i);
-+ goto done;
-+ }
-+ memcpy(data, fw_entry->data + offset, data_len);
-+ offset += data_len;
-+
-+ /* Sanity check */
-+ if (i >= nblocks){
-+ pr_err(PFX"%s Driver bug line %d\n", __func__, __LINE__);
-+ ret = -EINVAL;
-+ goto done;
-+ }
-+
-+ /* Validate header as appropriate */
-+ if (chdr == NULL){
-+ chdr = (efi_capsule_header_t*)&data[csh_jump];
-+ desc_block[i].data_block = __pa(&data[csh_jump]);
-+ desc_block[i].length = data_len - csh_jump;
-+ pr_debug(PFX"hdr offset in file %d bytes\n", csh_jump);
-+ pr_debug(PFX"hdr size %u flags 0x%08x imagesize 0x%08x\n",
-+ chdr->headersize, chdr->flags, chdr->imagesize);
-+
-+ }else{
-+ desc_block[i].data_block = __pa(data);
-+ desc_block[i].length = data_len;
-+ }
-+ pr_debug(PFX "block %d length %u data @ phys 0x%08x virt %x\n",
-+ i, (int)desc_block[i].length,
-+ (unsigned int)desc_block[i].data_block, data);
-+ }
-+
-+ if (i > nblocks-1){
-+ pr_err(PFX"%s Used block %d expected %d !\n", __func__, i, nblocks-1);
-+ ret = -EINVAL;
-+ goto done;
-+ }
-+
-+ pr_debug(PFX"submitting capsule to EDKII firmware\n");
-+
-+ ret = efi.update_capsule(&chdr, 1, __pa(desc_block));
-+ if(ret != EFI_SUCCESS) {
-+ pr_err(PFX"submission fail err=0x%08x\n", ret);
-+ }else{
-+ pr_debug(PFX"submission success\n");
-+ ret = 0;
-+ }
-+
-+ if (chdr != NULL && chdr->flags & 0x10000){
-+ pr_debug(PFX"capsule persist across S3 skipping capsule free\n");
-+ goto done_close;
-+ }
-+done:
-+
-+ for (i = 0; i < nblocks; i++){
-+ if (desc_block[i].data_block != 0)
-+ kfree(phys_to_virt((u32)desc_block[i].data_block));
-+ }
-+
-+ if (desc_block != NULL)
-+ kfree(desc_block);
-+done_close:
-+ release_firmware(fw_entry);
-+ return ret;
-+}
-+
-+/**
-+ * efi_capsule_csh_jump
-+ *
-+ * sysfs callback used to show current path
-+ */
-+static ssize_t efi_capsule_csh_jump_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return snprintf(buf, sizeof(fpath), "%d\n", csh_jump > 0);
-+}
-+
-+/**
-+ * efi_capsule_path_store
-+ *
-+ * sysfs callback used to set a new capsule path
-+ */
-+static ssize_t efi_capsule_csh_jump_store(struct kobject *kobj, struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ if (buf != NULL && buf[0] == '0')
-+ csh_jump = 0;
-+ else
-+ csh_jump = CSH_HDR_SIZE;
-+ return count;
-+}
-+
-+static struct kobj_attribute efi_capsule_csh_jump_attr =
-+ __ATTR(csh_jump, 0644, efi_capsule_csh_jump_show, efi_capsule_csh_jump_store);
-+
-+/**
-+ * efi_capsule_path_show
-+ *
-+ * sysfs callback used to show current path
-+ */
-+static ssize_t efi_capsule_path_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return snprintf(buf, sizeof(fpath), fpath);
-+}
-+
-+/**
-+ * efi_capsule_path_store
-+ *
-+ * sysfs callback used to set a new capsule path
-+ */
-+static ssize_t efi_capsule_path_store(struct kobject *kobj, struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ if (count > MAX_PATH-1)
-+ return -EINVAL;
-+
-+ memset(fpath, 0x00, sizeof(fpath));
-+ memcpy(fpath, buf, count);
-+ path_set = true;
-+
-+ return count;
-+}
-+
-+static struct kobj_attribute efi_capsule_path_attr =
-+ __ATTR(capsule_path, 0644, efi_capsule_path_show, efi_capsule_path_store);
-+
-+/**
-+ * efi_capsule_update_store
-+ *
-+ * sysfs callback used to initiate update
-+ */
-+static ssize_t efi_capsule_update_store(struct kobject *kobj, struct kobj_attribute *attr,
-+ const char *buf, size_t count)
-+{ int ret = 0;
-+
-+ ret = efi_capsule_trigger_update();
-+ return ret == 0 ? count : ret;
-+}
-+
-+static struct kobj_attribute efi_capsule_update_attr =
-+ __ATTR(capsule_update, 0644, NULL, efi_capsule_update_store);
-+
-+static void efi_capsule_device_release(struct device *dev)
-+{
-+ kfree(dev);
-+}
-+
-+#define SYSFS_ERRTXT "Error adding sysfs entry!\n"
-+/**
-+ * intel_cln_capsule_update_init
-+ *
-+ * @return 0 success < 0 failure
-+ *
-+ * Module entry point
-+ */
-+static int __init efi_capsule_update_init(void)
-+{
-+ int retval = 0;
-+ extern struct kobject * firmware_kobj;
-+
-+ INIT_LIST_HEAD(&sg_list);
-+
-+ /* efi_capsule_kobj subordinate of firmware @ /sys/firmware/efi */
-+ efi_capsule_kobj = kobject_create_and_add("efi_capsule", firmware_kobj);
-+ if (!efi_capsule_kobj) {
-+ pr_err(PFX"kset create error\n");
-+ retval = -ENODEV;
-+ goto err;
-+ }
-+
-+ dev = kzalloc(sizeof(struct device), GFP_KERNEL);
-+ if (!dev) {
-+ retval = -ENOMEM;
-+ goto err_name;
-+ }
-+
-+ retval = dev_set_name(dev, "%s", DRIVER_NAME);
-+ if (retval < 0){
-+ pr_err(PFX"dev_set_name err\n");
-+ goto err_dev_reg;
-+ }
-+
-+ dev->kobj.parent = efi_capsule_kobj;
-+ dev->groups = NULL;
-+ dev->release = efi_capsule_device_release;
-+
-+ retval = device_register(dev);
-+ if (retval < 0){
-+ pr_err(PFX"device_register error\n");
-+ goto err_dev_reg;
-+ }
-+
-+ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_path_attr.attr)) {
-+ pr_err(PFX SYSFS_ERRTXT);
-+ retval = -ENODEV;
-+ goto err_dev_reg;
-+ }
-+ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_update_attr.attr)) {
-+ pr_err(PFX SYSFS_ERRTXT);
-+ retval = -ENODEV;
-+ goto err_dev_reg;
-+
-+ }
-+ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_csh_jump_attr.attr)) {
-+ pr_err(PFX SYSFS_ERRTXT);
-+ retval = -ENODEV;
-+ goto err_dev_reg;
-+
-+ }
-+ return 0;
-+
-+err_dev_reg:
-+ put_device(dev);
-+ dev = NULL;
-+err_name:
-+ kfree(dev);
-+err:
-+ return retval;
-+}
-+
-+/**
-+ * intel_cln_esram_exit
-+ *
-+ * Module exit
-+ */
-+static void __exit efi_capsule_update_exit(void)
-+{
-+}
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("EFI Capsule Update driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+module_init(efi_capsule_update_init);
-+module_exit(efi_capsule_update_exit);
-diff --git a/drivers/base/class.c b/drivers/base/class.c
-index 03243d4..3ce8454 100644
---- a/drivers/base/class.c
-+++ b/drivers/base/class.c
-@@ -420,8 +420,8 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
- * code. There's no locking restriction.
- */
- struct device *class_find_device(struct class *class, struct device *start,
-- void *data,
-- int (*match)(struct device *, void *))
-+ const void *data,
-+ int (*match)(struct device *, const void *))
- {
- struct class_dev_iter iter;
- struct device *dev;
-diff --git a/drivers/base/core.c b/drivers/base/core.c
-index a235085..dda0c7f 100644
---- a/drivers/base/core.c
-+++ b/drivers/base/core.c
-@@ -1617,9 +1617,9 @@ struct device *device_create(struct class *class, struct device *parent,
- }
- EXPORT_SYMBOL_GPL(device_create);
-
--static int __match_devt(struct device *dev, void *data)
-+static int __match_devt(struct device *dev, const void *data)
- {
-- dev_t *devt = data;
-+ const dev_t *devt = data;
-
- return dev->devt == *devt;
- }
-diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
-index d4c1218..9867547 100644
---- a/drivers/dma/Kconfig
-+++ b/drivers/dma/Kconfig
-@@ -34,13 +34,13 @@ if DMADEVICES
- comment "DMA Devices"
-
- config INTEL_MID_DMAC
-- tristate "Intel MID DMA support for Peripheral DMA controllers"
-+ tristate "Intel DMAC Moorsetown/Medfield/Quark DMA controllers"
- depends on PCI && X86
- select DMA_ENGINE
- default n
- help
-- Enable support for the Intel(R) MID DMA engine present
-- in Intel MID chipsets.
-+ Enable support for the Intel(R) MID/Quark DMA engine present
-+ in Intel MID chipsets and Quark SOC devices
-
- Say Y here if you have such a chipset.
-
-diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
-index 7428fea..425587f 100644
---- a/drivers/dma/Makefile
-+++ b/drivers/dma/Makefile
-@@ -5,6 +5,7 @@ obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
- obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
- obj-$(CONFIG_NET_DMA) += iovlock.o
- obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
-+intel_mid_dma-objs:= intel_mid_dma_core.o intel_cln_dma_pci.o intel_mid_dma_pci.o
- obj-$(CONFIG_DMATEST) += dmatest.o
- obj-$(CONFIG_INTEL_IOATDMA) += ioat/
- obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
-diff --git a/drivers/dma/intel_cln_dma_pci.c b/drivers/dma/intel_cln_dma_pci.c
-new file mode 100644
-index 0000000..cb3d6e7
---- /dev/null
-+++ b/drivers/dma/intel_cln_dma_pci.c
-@@ -0,0 +1,155 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+
-+/*
-+ * intel_quark_dma_pci.c
-+ *
-+ * Author: Bryan O'Donoghue <bryan.odonoghue@intel.com>
-+ * This is an entry point for Intel Quark based DMAC on Quark's UART
-+ * specifically we don't have a dedicated PCI function, instead we have DMAC
-+ * regs hung off of a PCI BAR. This entry/exit allows re-use of the core
-+ * DMA API for MID devices manipulated to suit our BAR setup
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ */
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/intel_mid_dma.h>
-+#include <linux/module.h>
-+
-+//#include "intel_mid_dma_core.h"
-+#include "intel_mid_dma_regs.h"
-+
-+/**
-+ * intel_mid_dma_probe - PCI Probe
-+ * @pdev: Controller PCI device structure
-+ * @id: pci device id structure
-+ *
-+ * Initialize the PCI device, map BARs, query driver data.
-+ * Call mid_setup_dma to complete contoller and chan initilzation
-+ */
-+int intel_cln_dma_probe(struct pci_dev *pdev,
-+ struct middma_device *device)
-+{
-+ u32 base_addr, bar_size;
-+ int err;
-+
-+ dev_info(&pdev->dev, "MDMA: probe for %x\n", pdev->device);
-+ dev_info(&pdev->dev, "MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
-+ device->max_chan, device->chan_base,
-+ device->block_size, device->pimr_mask);
-+
-+ device->pdev = pci_dev_get(pdev);
-+
-+ base_addr = pci_resource_start(pdev, 1);
-+ bar_size = pci_resource_len(pdev, 1);
-+ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
-+ if (!device->dma_base) {
-+ pr_err("ERR_MDMA:ioremap failed\n");
-+ err = -ENOMEM;
-+ goto err_ioremap;
-+ }
-+
-+ dev_info(&pdev->dev, "Remapped BAR 0x%08x to virt 0x%p\n",
-+ base_addr, device->dma_base);
-+
-+ err = mid_setup_dma(pdev, device);
-+ if (err)
-+ goto err_dma;
-+
-+ return 0;
-+
-+err_dma:
-+ iounmap(device->dma_base);
-+err_ioremap:
-+ pr_err("ERR_MDMA:Probe failed %d\n", err);
-+ return err;
-+}
-+EXPORT_SYMBOL(intel_cln_dma_probe);
-+
-+/**
-+ * intel_mid_dma_remove - PCI remove
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Free up all resources and data
-+ * Call shutdown_dma to complete contoller and chan cleanup
-+ */
-+void intel_cln_dma_remove(struct pci_dev *pdev, struct middma_device *device)
-+{
-+ //middma_shutdown(pdev, device);
-+}
-+EXPORT_SYMBOL(intel_cln_dma_remove);
-+
-+/* Power Management */
-+/*
-+* dma_suspend - PCI suspend function
-+*
-+* @pci: PCI device structure
-+* @state: PM message
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+int intel_cln_dma_suspend(struct middma_device *device)
-+{
-+ int i = 0;
-+ pr_debug("MDMA: dma_suspend called\n");
-+
-+ for (i = 0; i < device->max_chan; i++) {
-+ if (device->ch[i].in_use)
-+ return -EAGAIN;
-+ }
-+#if 0
-+ dmac1_mask_periphral_intr(device);
-+#endif
-+ device->state = SUSPENDED;
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_dma_suspend);
-+
-+/**
-+* dma_resume - PCI resume function
-+*
-+* @pci: PCI device structure
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+int intel_cln_dma_resume(struct middma_device *device)
-+{
-+ //return middma_resume(device);
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_dma_resume);
-+
-+static int intel_cln_dma_runtime_suspend(struct middma_device *device)
-+{
-+ device->state = SUSPENDED;
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_dma_runtime_suspend);
-+
-+static int intel_cln_dma_runtime_resume(struct middma_device *device)
-+{
-+ device->state = RUNNING;
-+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_dma_runtime_resume);
-+
-+
-diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
-deleted file mode 100644
-index a0de82e..0000000
---- a/drivers/dma/intel_mid_dma.c
-+++ /dev/null
-@@ -1,1460 +0,0 @@
--/*
-- * intel_mid_dma.c - Intel Langwell DMA Drivers
-- *
-- * Copyright (C) 2008-10 Intel Corp
-- * Author: Vinod Koul <vinod.koul@intel.com>
-- * The driver design is based on dw_dmac driver
-- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- *
-- * This program is free software; you can redistribute it and/or modify
-- * it under the terms of the GNU General Public License as published by
-- * the Free Software Foundation; version 2 of the License.
-- *
-- * This program is distributed in the hope that it will be useful, but
-- * WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- * General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License along
-- * with this program; if not, write to the Free Software Foundation, Inc.,
-- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-- *
-- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- *
-- *
-- */
--#include <linux/pci.h>
--#include <linux/interrupt.h>
--#include <linux/pm_runtime.h>
--#include <linux/intel_mid_dma.h>
--#include <linux/module.h>
--
--#include "dmaengine.h"
--
--#define MAX_CHAN 4 /*max ch across controllers*/
--#include "intel_mid_dma_regs.h"
--
--#define INTEL_MID_DMAC1_ID 0x0814
--#define INTEL_MID_DMAC2_ID 0x0813
--#define INTEL_MID_GP_DMAC2_ID 0x0827
--#define INTEL_MFLD_DMAC1_ID 0x0830
--#define LNW_PERIPHRAL_MASK_BASE 0xFFAE8008
--#define LNW_PERIPHRAL_MASK_SIZE 0x10
--#define LNW_PERIPHRAL_STATUS 0x0
--#define LNW_PERIPHRAL_MASK 0x8
--
--struct intel_mid_dma_probe_info {
-- u8 max_chan;
-- u8 ch_base;
-- u16 block_size;
-- u32 pimr_mask;
--};
--
--#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
-- ((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*/
--/**
-- * get_ch_index - convert status to channel
-- * @status: status mask
-- * @base: dma ch base value
-- *
-- * Modify the status mask and return the channel index needing
-- * attention (or -1 if neither)
-- */
--static int get_ch_index(int *status, unsigned int base)
--{
-- int i;
-- for (i = 0; i < MAX_CHAN; i++) {
-- if (*status & (1 << (i + base))) {
-- *status = *status & ~(1 << (i + base));
-- pr_debug("MDMA: index %d New status %x\n", i, *status);
-- return i;
-- }
-- }
-- return -1;
--}
--
--/**
-- * get_block_ts - calculates dma transaction length
-- * @len: dma transfer length
-- * @tx_width: dma transfer src width
-- * @block_size: dma controller max block size
-- *
-- * Based on src width calculate the DMA trsaction length in data items
-- * return data items or FFFF if exceeds max length for block
-- */
--static int get_block_ts(int len, int tx_width, int block_size)
--{
-- int byte_width = 0, block_ts = 0;
--
-- switch (tx_width) {
-- case DMA_SLAVE_BUSWIDTH_1_BYTE:
-- byte_width = 1;
-- break;
-- case DMA_SLAVE_BUSWIDTH_2_BYTES:
-- byte_width = 2;
-- break;
-- case DMA_SLAVE_BUSWIDTH_4_BYTES:
-- default:
-- byte_width = 4;
-- break;
-- }
--
-- block_ts = len/byte_width;
-- if (block_ts > block_size)
-- block_ts = 0xFFFF;
-- return block_ts;
--}
--
--/*****************************************************************************
--DMAC1 interrupt Functions*/
--
--/**
-- * dmac1_mask_periphral_intr - mask the periphral interrupt
-- * @mid: dma device for which masking is required
-- *
-- * Masks the DMA periphral interrupt
-- * this is valid for DMAC1 family controllers only
-- * This controller should have periphral mask registers already mapped
-- */
--static void dmac1_mask_periphral_intr(struct middma_device *mid)
--{
-- u32 pimr;
--
-- if (mid->pimr_mask) {
-- pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
-- pimr |= mid->pimr_mask;
-- writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
-- }
-- return;
--}
--
--/**
-- * dmac1_unmask_periphral_intr - unmask the periphral interrupt
-- * @midc: dma channel for which masking is required
-- *
-- * UnMasks the DMA periphral interrupt,
-- * this is valid for DMAC1 family controllers only
-- * This controller should have periphral mask registers already mapped
-- */
--static void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
--{
-- u32 pimr;
-- struct middma_device *mid = to_middma_device(midc->chan.device);
--
-- if (mid->pimr_mask) {
-- pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
-- pimr &= ~mid->pimr_mask;
-- writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
-- }
-- return;
--}
--
--/**
-- * enable_dma_interrupt - enable the periphral interrupt
-- * @midc: dma channel for which enable interrupt is required
-- *
-- * Enable the DMA periphral interrupt,
-- * this is valid for DMAC1 family controllers only
-- * This controller should have periphral mask registers already mapped
-- */
--static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
--{
-- dmac1_unmask_periphral_intr(midc);
--
-- /*en ch interrupts*/
-- iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
-- iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
-- return;
--}
--
--/**
-- * disable_dma_interrupt - disable the periphral interrupt
-- * @midc: dma channel for which disable interrupt is required
-- *
-- * Disable the DMA periphral interrupt,
-- * this is valid for DMAC1 family controllers only
-- * This controller should have periphral mask registers already mapped
-- */
--static void disable_dma_interrupt(struct intel_mid_dma_chan *midc)
--{
-- /*Check LPE PISR, make sure fwd is disabled*/
-- iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK);
-- iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
-- iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
-- return;
--}
--
--/*****************************************************************************
--DMA channel helper Functions*/
--/**
-- * mid_desc_get - get a descriptor
-- * @midc: dma channel for which descriptor is required
-- *
-- * Obtain a descriptor for the channel. Returns NULL if none are free.
-- * Once the descriptor is returned it is private until put on another
-- * list or freed
-- */
--static struct intel_mid_dma_desc *midc_desc_get(struct intel_mid_dma_chan *midc)
--{
-- struct intel_mid_dma_desc *desc, *_desc;
-- struct intel_mid_dma_desc *ret = NULL;
--
-- spin_lock_bh(&midc->lock);
-- list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
-- if (async_tx_test_ack(&desc->txd)) {
-- list_del(&desc->desc_node);
-- ret = desc;
-- break;
-- }
-- }
-- spin_unlock_bh(&midc->lock);
-- return ret;
--}
--
--/**
-- * mid_desc_put - put a descriptor
-- * @midc: dma channel for which descriptor is required
-- * @desc: descriptor to put
-- *
-- * Return a descriptor from lwn_desc_get back to the free pool
-- */
--static void midc_desc_put(struct intel_mid_dma_chan *midc,
-- struct intel_mid_dma_desc *desc)
--{
-- if (desc) {
-- spin_lock_bh(&midc->lock);
-- list_add_tail(&desc->desc_node, &midc->free_list);
-- spin_unlock_bh(&midc->lock);
-- }
--}
--/**
-- * midc_dostart - begin a DMA transaction
-- * @midc: channel for which txn is to be started
-- * @first: first descriptor of series
-- *
-- * Load a transaction into the engine. This must be called with midc->lock
-- * held and bh disabled.
-- */
--static void midc_dostart(struct intel_mid_dma_chan *midc,
-- struct intel_mid_dma_desc *first)
--{
-- struct middma_device *mid = to_middma_device(midc->chan.device);
--
-- /* channel is idle */
-- if (midc->busy && test_ch_en(midc->dma_base, midc->ch_id)) {
-- /*error*/
-- pr_err("ERR_MDMA: channel is busy in start\n");
-- /* The tasklet will hopefully advance the queue... */
-- return;
-- }
-- midc->busy = true;
-- /*write registers and en*/
-- iowrite32(first->sar, midc->ch_regs + SAR);
-- iowrite32(first->dar, midc->ch_regs + DAR);
-- iowrite32(first->lli_phys, midc->ch_regs + LLP);
-- iowrite32(first->cfg_hi, midc->ch_regs + CFG_HIGH);
-- iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
-- iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
-- iowrite32(first->ctl_hi, midc->ch_regs + CTL_HIGH);
-- pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
-- (int)first->sar, (int)first->dar, first->cfg_hi,
-- first->cfg_lo, first->ctl_hi, first->ctl_lo);
-- first->status = DMA_IN_PROGRESS;
--
-- iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
--}
--
--/**
-- * midc_descriptor_complete - process completed descriptor
-- * @midc: channel owning the descriptor
-- * @desc: the descriptor itself
-- *
-- * Process a completed descriptor and perform any callbacks upon
-- * the completion. The completion handling drops the lock during the
-- * callbacks but must be called with the lock held.
-- */
--static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
-- struct intel_mid_dma_desc *desc)
-- __releases(&midc->lock) __acquires(&midc->lock)
--{
-- struct dma_async_tx_descriptor *txd = &desc->txd;
-- dma_async_tx_callback callback_txd = NULL;
-- struct intel_mid_dma_lli *llitem;
-- void *param_txd = NULL;
--
-- 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;
-- llitem->ctl_hi &= CLEAR_DONE;
-- if (desc->current_lli < desc->lli_length-1)
-- (desc->current_lli)++;
-- else
-- desc->current_lli = 0;
-- }
-- spin_unlock_bh(&midc->lock);
-- if (callback_txd) {
-- pr_debug("MDMA: TXD callback set ... calling\n");
-- callback_txd(param_txd);
-- }
-- if (midc->raw_tfr) {
-- desc->status = DMA_SUCCESS;
-- if (desc->lli != NULL) {
-- pci_pool_free(desc->lli_pool, desc->lli,
-- desc->lli_phys);
-- pci_pool_destroy(desc->lli_pool);
-- desc->lli = NULL;
-- }
-- list_move(&desc->desc_node, &midc->free_list);
-- midc->busy = false;
-- }
-- spin_lock_bh(&midc->lock);
--
--}
--/**
-- * midc_scan_descriptors - check the descriptors in channel
-- * mark completed when tx is completete
-- * @mid: device
-- * @midc: channel to scan
-- *
-- * Walk the descriptor chain for the device and process any entries
-- * that are complete.
-- */
--static void midc_scan_descriptors(struct middma_device *mid,
-- struct intel_mid_dma_chan *midc)
--{
-- struct intel_mid_dma_desc *desc = NULL, *_desc = NULL;
--
-- /*tx is complete*/
-- list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-- if (desc->status == DMA_IN_PROGRESS)
-- midc_descriptor_complete(midc, desc);
-- }
-- return;
-- }
--/**
-- * midc_lli_fill_sg - Helper function to convert
-- * SG list to Linked List Items.
-- *@midc: Channel
-- *@desc: DMA descriptor
-- *@sglist: Pointer to SG list
-- *@sglen: SG list length
-- *@flags: DMA transaction flags
-- *
-- * Walk through the SG list and convert the SG list into Linked
-- * List Items (LLI).
-- */
--static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
-- struct intel_mid_dma_desc *desc,
-- struct scatterlist *sglist,
-- unsigned int sglen,
-- unsigned int flags)
--{
-- struct intel_mid_dma_slave *mids;
-- struct scatterlist *sg;
-- dma_addr_t lli_next, sg_phy_addr;
-- struct intel_mid_dma_lli *lli_bloc_desc;
-- union intel_mid_dma_ctl_lo ctl_lo;
-- union intel_mid_dma_ctl_hi ctl_hi;
-- int i;
--
-- pr_debug("MDMA: Entered midc_lli_fill_sg\n");
-- mids = midc->mid_slave;
--
-- lli_bloc_desc = desc->lli;
-- lli_next = desc->lli_phys;
--
-- ctl_lo.ctl_lo = desc->ctl_lo;
-- ctl_hi.ctl_hi = desc->ctl_hi;
-- for_each_sg(sglist, sg, sglen, i) {
-- /*Populate CTL_LOW and LLI values*/
-- if (i != sglen - 1) {
-- lli_next = lli_next +
-- sizeof(struct intel_mid_dma_lli);
-- } else {
-- /*Check for circular list, otherwise terminate LLI to ZERO*/
-- if (flags & DMA_PREP_CIRCULAR_LIST) {
-- pr_debug("MDMA: LLI is configured in circular mode\n");
-- lli_next = desc->lli_phys;
-- } else {
-- lli_next = 0;
-- ctl_lo.ctlx.llp_dst_en = 0;
-- ctl_lo.ctlx.llp_src_en = 0;
-- }
-- }
-- /*Populate CTL_HI values*/
-- ctl_hi.ctlx.block_ts = get_block_ts(sg_dma_len(sg),
-- desc->width,
-- midc->dma->block_size);
-- /*Populate SAR and DAR values*/
-- sg_phy_addr = sg_dma_address(sg);
-- if (desc->dirn == DMA_MEM_TO_DEV) {
-- lli_bloc_desc->sar = sg_phy_addr;
-- lli_bloc_desc->dar = mids->dma_slave.dst_addr;
-- } else if (desc->dirn == DMA_DEV_TO_MEM) {
-- lli_bloc_desc->sar = mids->dma_slave.src_addr;
-- lli_bloc_desc->dar = sg_phy_addr;
-- }
-- /*Copy values into block descriptor in system memroy*/
-- lli_bloc_desc->llp = lli_next;
-- lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
-- lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
--
-- lli_bloc_desc++;
-- }
-- /*Copy very first LLI values to descriptor*/
-- desc->ctl_lo = desc->lli->ctl_lo;
-- desc->ctl_hi = desc->lli->ctl_hi;
-- desc->sar = desc->lli->sar;
-- desc->dar = desc->lli->dar;
--
-- return 0;
--}
--/*****************************************************************************
--DMA engine callback Functions*/
--/**
-- * intel_mid_dma_tx_submit - callback to submit DMA transaction
-- * @tx: dma engine descriptor
-- *
-- * Submit the DMA transaction for this descriptor, start if ch idle
-- */
--static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
--{
-- struct intel_mid_dma_desc *desc = to_intel_mid_dma_desc(tx);
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(tx->chan);
-- dma_cookie_t cookie;
--
-- spin_lock_bh(&midc->lock);
-- cookie = dma_cookie_assign(tx);
--
-- if (list_empty(&midc->active_list))
-- list_add_tail(&desc->desc_node, &midc->active_list);
-- else
-- list_add_tail(&desc->desc_node, &midc->queue);
--
-- midc_dostart(midc, desc);
-- spin_unlock_bh(&midc->lock);
--
-- return cookie;
--}
--
--/**
-- * intel_mid_dma_issue_pending - callback to issue pending txn
-- * @chan: chan where pending trascation needs to be checked and submitted
-- *
-- * Call for scan to issue pending descriptors
-- */
--static void intel_mid_dma_issue_pending(struct dma_chan *chan)
--{
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
--
-- spin_lock_bh(&midc->lock);
-- if (!list_empty(&midc->queue))
-- midc_scan_descriptors(to_middma_device(chan->device), midc);
-- spin_unlock_bh(&midc->lock);
--}
--
--/**
-- * intel_mid_dma_tx_status - Return status of txn
-- * @chan: chan for where status needs to be checked
-- * @cookie: cookie for txn
-- * @txstate: DMA txn state
-- *
-- * Return status of DMA txn
-- */
--static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
-- dma_cookie_t cookie,
-- struct dma_tx_state *txstate)
--{
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-- enum dma_status ret;
--
-- ret = dma_cookie_status(chan, cookie, txstate);
-- if (ret != DMA_SUCCESS) {
-- spin_lock_bh(&midc->lock);
-- midc_scan_descriptors(to_middma_device(chan->device), midc);
-- spin_unlock_bh(&midc->lock);
--
-- ret = dma_cookie_status(chan, cookie, txstate);
-- }
--
-- return ret;
--}
--
--static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
--{
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-- struct dma_slave_config *slave = (struct dma_slave_config *)arg;
-- struct intel_mid_dma_slave *mid_slave;
--
-- BUG_ON(!midc);
-- BUG_ON(!slave);
-- pr_debug("MDMA: slave control called\n");
--
-- mid_slave = to_intel_mid_dma_slave(slave);
--
-- BUG_ON(!mid_slave);
--
-- midc->mid_slave = mid_slave;
-- return 0;
--}
--/**
-- * intel_mid_dma_device_control - DMA device control
-- * @chan: chan for DMA control
-- * @cmd: control cmd
-- * @arg: cmd arg value
-- *
-- * Perform DMA control command
-- */
--static int intel_mid_dma_device_control(struct dma_chan *chan,
-- enum dma_ctrl_cmd cmd, unsigned long arg)
--{
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-- struct middma_device *mid = to_middma_device(chan->device);
-- struct intel_mid_dma_desc *desc, *_desc;
-- union intel_mid_dma_cfg_lo cfg_lo;
--
-- if (cmd == DMA_SLAVE_CONFIG)
-- return dma_slave_control(chan, arg);
--
-- if (cmd != DMA_TERMINATE_ALL)
-- return -ENXIO;
--
-- spin_lock_bh(&midc->lock);
-- if (midc->busy == false) {
-- spin_unlock_bh(&midc->lock);
-- return 0;
-- }
-- /*Suspend and disable the channel*/
-- cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
-- cfg_lo.cfgx.ch_susp = 1;
-- iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
-- iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
-- midc->busy = false;
-- /* Disable interrupts */
-- disable_dma_interrupt(midc);
-- midc->descs_allocated = 0;
--
-- spin_unlock_bh(&midc->lock);
-- list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-- if (desc->lli != NULL) {
-- pci_pool_free(desc->lli_pool, desc->lli,
-- desc->lli_phys);
-- pci_pool_destroy(desc->lli_pool);
-- desc->lli = NULL;
-- }
-- list_move(&desc->desc_node, &midc->free_list);
-- }
-- return 0;
--}
--
--
--/**
-- * intel_mid_dma_prep_memcpy - Prep memcpy txn
-- * @chan: chan for DMA transfer
-- * @dest: destn address
-- * @src: src address
-- * @len: DMA transfer len
-- * @flags: DMA flags
-- *
-- * Perform a DMA memcpy. Note we support slave periphral DMA transfers only
-- * The periphral txn details should be filled in slave structure properly
-- * Returns the descriptor for this txn
-- */
--static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
-- struct dma_chan *chan, dma_addr_t dest,
-- dma_addr_t src, size_t len, unsigned long flags)
--{
-- struct intel_mid_dma_chan *midc;
-- struct intel_mid_dma_desc *desc = NULL;
-- struct intel_mid_dma_slave *mids;
-- union intel_mid_dma_ctl_lo ctl_lo;
-- union intel_mid_dma_ctl_hi ctl_hi;
-- union intel_mid_dma_cfg_lo cfg_lo;
-- union intel_mid_dma_cfg_hi cfg_hi;
-- enum dma_slave_buswidth width;
--
-- pr_debug("MDMA: Prep for memcpy\n");
-- BUG_ON(!chan);
-- if (!len)
-- return NULL;
--
-- midc = to_intel_mid_dma_chan(chan);
-- BUG_ON(!midc);
--
-- 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",
-- mids->cfg_mode, mids->dma_slave.direction,
-- mids->hs_mode, mids->dma_slave.src_addr_width);
--
-- /*calculate CFG_LO*/
-- if (mids->hs_mode == LNW_DMA_SW_HS) {
-- cfg_lo.cfg_lo = 0;
-- cfg_lo.cfgx.hs_sel_dst = 1;
-- cfg_lo.cfgx.hs_sel_src = 1;
-- } else if (mids->hs_mode == LNW_DMA_HW_HS)
-- cfg_lo.cfg_lo = 0x00000;
--
-- /*calculate CFG_HI*/
-- if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
-- /*SW HS only*/
-- cfg_hi.cfg_hi = 0;
-- } else {
-- cfg_hi.cfg_hi = 0;
-- if (midc->dma->pimr_mask) {
-- cfg_hi.cfgx.protctl = 0x0; /*default value*/
-- cfg_hi.cfgx.fifo_mode = 1;
-- if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
-- cfg_hi.cfgx.src_per = 0;
-- if (mids->device_instance == 0)
-- cfg_hi.cfgx.dst_per = 3;
-- if (mids->device_instance == 1)
-- cfg_hi.cfgx.dst_per = 1;
-- } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
-- if (mids->device_instance == 0)
-- cfg_hi.cfgx.src_per = 2;
-- if (mids->device_instance == 1)
-- cfg_hi.cfgx.src_per = 0;
-- cfg_hi.cfgx.dst_per = 0;
-- }
-- } else {
-- cfg_hi.cfgx.protctl = 0x1; /*default value*/
-- cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
-- midc->ch_id - midc->dma->chan_base;
-- }
-- }
--
-- /*calculate CTL_HI*/
-- ctl_hi.ctlx.reser = 0;
-- ctl_hi.ctlx.done = 0;
-- width = mids->dma_slave.src_addr_width;
--
-- ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
-- pr_debug("MDMA:calc len %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;
--
-- /*
-- * Here we need some translation from "enum dma_slave_buswidth"
-- * to the format for our dma controller
-- * standard intel_mid_dmac's format
-- * 1 Byte 0b000
-- * 2 Bytes 0b001
-- * 4 Bytes 0b010
-- */
-- ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
-- ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
--
-- if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
-- ctl_lo.ctlx.tt_fc = 0;
-- ctl_lo.ctlx.sinc = 0;
-- ctl_lo.ctlx.dinc = 0;
-- } else {
-- if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
-- ctl_lo.ctlx.sinc = 0;
-- ctl_lo.ctlx.dinc = 2;
-- ctl_lo.ctlx.tt_fc = 1;
-- } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
-- ctl_lo.ctlx.sinc = 2;
-- ctl_lo.ctlx.dinc = 0;
-- ctl_lo.ctlx.tt_fc = 2;
-- }
-- }
--
-- pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
-- ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
--
-- enable_dma_interrupt(midc);
--
-- desc = midc_desc_get(midc);
-- if (desc == NULL)
-- goto err_desc_get;
-- desc->sar = src;
-- desc->dar = dest ;
-- desc->len = len;
-- desc->cfg_hi = cfg_hi.cfg_hi;
-- desc->cfg_lo = cfg_lo.cfg_lo;
-- desc->ctl_lo = ctl_lo.ctl_lo;
-- desc->ctl_hi = ctl_hi.ctl_hi;
-- desc->width = width;
-- desc->dirn = mids->dma_slave.direction;
-- desc->lli_phys = 0;
-- desc->lli = NULL;
-- desc->lli_pool = NULL;
-- return &desc->txd;
--
--err_desc_get:
-- pr_err("ERR_MDMA: Failed to get desc\n");
-- midc_desc_put(midc, desc);
-- return NULL;
--}
--/**
-- * intel_mid_dma_prep_slave_sg - Prep slave sg txn
-- * @chan: chan for DMA transfer
-- * @sgl: scatter gather list
-- * @sg_len: length of sg txn
-- * @direction: DMA transfer dirtn
-- * @flags: DMA flags
-- * @context: transfer context (ignored)
-- *
-- * Prepares LLI based periphral transfer
-- */
--static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
-- struct dma_chan *chan, struct scatterlist *sgl,
-- unsigned int sg_len, enum dma_transfer_direction direction,
-- unsigned long flags, void *context)
--{
-- struct intel_mid_dma_chan *midc = NULL;
-- struct intel_mid_dma_slave *mids = NULL;
-- struct intel_mid_dma_desc *desc = NULL;
-- struct dma_async_tx_descriptor *txd = NULL;
-- union intel_mid_dma_ctl_lo ctl_lo;
--
-- pr_debug("MDMA: Prep for slave SG\n");
--
-- if (!sg_len) {
-- pr_err("MDMA: Invalid SG length\n");
-- return NULL;
-- }
-- midc = to_intel_mid_dma_chan(chan);
-- BUG_ON(!midc);
--
-- mids = midc->mid_slave;
-- BUG_ON(!mids);
--
-- if (!midc->dma->pimr_mask) {
-- /* We can still handle sg list with only one item */
-- if (sg_len == 1) {
-- txd = intel_mid_dma_prep_memcpy(chan,
-- mids->dma_slave.dst_addr,
-- mids->dma_slave.src_addr,
-- sg_dma_len(sgl),
-- flags);
-- return txd;
-- } else {
-- pr_warn("MDMA: SG list is not supported by this controller\n");
-- return NULL;
-- }
-- }
--
-- pr_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);
-- if (NULL == txd) {
-- pr_err("MDMA: Prep memcpy failed\n");
-- return NULL;
-- }
--
-- desc = to_intel_mid_dma_desc(txd);
-- desc->dirn = direction;
-- ctl_lo.ctl_lo = desc->ctl_lo;
-- ctl_lo.ctlx.llp_dst_en = 1;
-- ctl_lo.ctlx.llp_src_en = 1;
-- desc->ctl_lo = ctl_lo.ctl_lo;
-- desc->lli_length = sg_len;
-- desc->current_lli = 0;
-- /* DMA coherent memory pool for LLI descriptors*/
-- desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
-- midc->dma->pdev,
-- (sizeof(struct intel_mid_dma_lli)*sg_len),
-- 32, 0);
-- if (NULL == desc->lli_pool) {
-- pr_err("MID_DMA:LLI pool create failed\n");
-- return NULL;
-- }
--
-- desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
-- if (!desc->lli) {
-- pr_err("MID_DMA: LLI alloc failed\n");
-- pci_pool_destroy(desc->lli_pool);
-- return NULL;
-- }
--
-- midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
-- if (flags & DMA_PREP_INTERRUPT) {
-- iowrite32(UNMASK_INTR_REG(midc->ch_id),
-- midc->dma_base + MASK_BLOCK);
-- pr_debug("MDMA:Enabled Block interrupt\n");
-- }
-- return &desc->txd;
--}
--
--/**
-- * intel_mid_dma_free_chan_resources - Frees dma resources
-- * @chan: chan requiring attention
-- *
-- * Frees the allocated resources on this DMA chan
-- */
--static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
--{
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-- struct middma_device *mid = to_middma_device(chan->device);
-- struct intel_mid_dma_desc *desc, *_desc;
--
-- if (true == midc->busy) {
-- /*trying to free ch in use!!!!!*/
-- pr_err("ERR_MDMA: trying to free ch in use\n");
-- }
-- spin_lock_bh(&midc->lock);
-- midc->descs_allocated = 0;
-- list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-- list_del(&desc->desc_node);
-- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
-- }
-- list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
-- list_del(&desc->desc_node);
-- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
-- }
-- list_for_each_entry_safe(desc, _desc, &midc->queue, desc_node) {
-- list_del(&desc->desc_node);
-- pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
-- }
-- spin_unlock_bh(&midc->lock);
-- midc->in_use = false;
-- midc->busy = false;
-- /* Disable CH interrupts */
-- iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
-- iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
-- pm_runtime_put(&mid->pdev->dev);
--}
--
--/**
-- * intel_mid_dma_alloc_chan_resources - Allocate dma resources
-- * @chan: chan requiring attention
-- *
-- * Allocates DMA resources on this chan
-- * Return the descriptors allocated
-- */
--static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
--{
-- struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-- struct middma_device *mid = to_middma_device(chan->device);
-- struct intel_mid_dma_desc *desc;
-- dma_addr_t phys;
-- int i = 0;
--
-- pm_runtime_get_sync(&mid->pdev->dev);
--
-- if (mid->state == SUSPENDED) {
-- if (dma_resume(&mid->pdev->dev)) {
-- pr_err("ERR_MDMA: resume failed");
-- return -EFAULT;
-- }
-- }
--
-- /* ASSERT: channel is idle */
-- if (test_ch_en(mid->dma_base, midc->ch_id)) {
-- /*ch is not idle*/
-- pr_err("ERR_MDMA: ch not idle\n");
-- pm_runtime_put(&mid->pdev->dev);
-- return -EIO;
-- }
-- dma_cookie_init(chan);
--
-- spin_lock_bh(&midc->lock);
-- while (midc->descs_allocated < DESCS_PER_CHANNEL) {
-- spin_unlock_bh(&midc->lock);
-- desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
-- if (!desc) {
-- pr_err("ERR_MDMA: desc failed\n");
-- pm_runtime_put(&mid->pdev->dev);
-- return -ENOMEM;
-- /*check*/
-- }
-- dma_async_tx_descriptor_init(&desc->txd, chan);
-- desc->txd.tx_submit = intel_mid_dma_tx_submit;
-- desc->txd.flags = DMA_CTRL_ACK;
-- desc->txd.phys = phys;
-- spin_lock_bh(&midc->lock);
-- i = ++midc->descs_allocated;
-- list_add_tail(&desc->desc_node, &midc->free_list);
-- }
-- spin_unlock_bh(&midc->lock);
-- midc->in_use = true;
-- midc->busy = false;
-- pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
-- return i;
--}
--
--/**
-- * midc_handle_error - Handle DMA txn error
-- * @mid: controller where error occurred
-- * @midc: chan where error occurred
-- *
-- * Scan the descriptor for error
-- */
--static void midc_handle_error(struct middma_device *mid,
-- struct intel_mid_dma_chan *midc)
--{
-- midc_scan_descriptors(mid, midc);
--}
--
--/**
-- * dma_tasklet - DMA interrupt tasklet
-- * @data: tasklet arg (the controller structure)
-- *
-- * Scan the controller for interrupts for completion/error
-- * Clear the interrupt and call for handling completion/error
-- */
--static void dma_tasklet(unsigned long data)
--{
-- struct middma_device *mid = NULL;
-- struct intel_mid_dma_chan *midc = NULL;
-- u32 status, raw_tfr, raw_block;
-- int i;
--
-- mid = (struct middma_device *)data;
-- if (mid == NULL) {
-- pr_err("ERR_MDMA: tasklet Null param\n");
-- return;
-- }
-- pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
-- raw_tfr = ioread32(mid->dma_base + RAW_TFR);
-- raw_block = ioread32(mid->dma_base + RAW_BLOCK);
-- status = raw_tfr | raw_block;
-- status &= mid->intr_mask;
-- while (status) {
-- /*txn interrupt*/
-- i = get_ch_index(&status, mid->chan_base);
-- if (i < 0) {
-- pr_err("ERR_MDMA:Invalid ch index %x\n", i);
-- return;
-- }
-- midc = &mid->ch[i];
-- if (midc == NULL) {
-- pr_err("ERR_MDMA:Null param midc\n");
-- return;
-- }
-- pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
-- status, midc->ch_id, i);
-- midc->raw_tfr = raw_tfr;
-- midc->raw_block = raw_block;
-- spin_lock_bh(&midc->lock);
-- /*clearing this interrupts first*/
-- iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
-- if (raw_block) {
-- iowrite32((1 << midc->ch_id),
-- mid->dma_base + CLEAR_BLOCK);
-- }
-- midc_scan_descriptors(mid, midc);
-- pr_debug("MDMA:Scan of desc... complete, unmasking\n");
-- iowrite32(UNMASK_INTR_REG(midc->ch_id),
-- mid->dma_base + MASK_TFR);
-- if (raw_block) {
-- iowrite32(UNMASK_INTR_REG(midc->ch_id),
-- mid->dma_base + MASK_BLOCK);
-- }
-- spin_unlock_bh(&midc->lock);
-- }
--
-- status = ioread32(mid->dma_base + RAW_ERR);
-- status &= mid->intr_mask;
-- while (status) {
-- /*err interrupt*/
-- i = get_ch_index(&status, mid->chan_base);
-- if (i < 0) {
-- pr_err("ERR_MDMA:Invalid ch index %x\n", i);
-- return;
-- }
-- midc = &mid->ch[i];
-- if (midc == NULL) {
-- pr_err("ERR_MDMA:Null param midc\n");
-- return;
-- }
-- pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
-- status, midc->ch_id, i);
--
-- iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_ERR);
-- spin_lock_bh(&midc->lock);
-- midc_handle_error(mid, midc);
-- iowrite32(UNMASK_INTR_REG(midc->ch_id),
-- mid->dma_base + MASK_ERR);
-- spin_unlock_bh(&midc->lock);
-- }
-- pr_debug("MDMA:Exiting takslet...\n");
-- return;
--}
--
--static void dma_tasklet1(unsigned long data)
--{
-- pr_debug("MDMA:in takslet1...\n");
-- return dma_tasklet(data);
--}
--
--static void dma_tasklet2(unsigned long data)
--{
-- pr_debug("MDMA:in takslet2...\n");
-- return dma_tasklet(data);
--}
--
--/**
-- * intel_mid_dma_interrupt - DMA ISR
-- * @irq: IRQ where interrupt occurred
-- * @data: ISR cllback data (the controller structure)
-- *
-- * See if this is our interrupt if so then schedule the tasklet
-- * otherwise ignore
-- */
--static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
--{
-- struct middma_device *mid = data;
-- u32 tfr_status, err_status;
-- int call_tasklet = 0;
--
-- tfr_status = ioread32(mid->dma_base + RAW_TFR);
-- err_status = ioread32(mid->dma_base + RAW_ERR);
-- if (!tfr_status && !err_status)
-- return IRQ_NONE;
--
-- /*DMA Interrupt*/
-- pr_debug("MDMA:Got an interrupt on irq %d\n", irq);
-- pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask);
-- tfr_status &= mid->intr_mask;
-- if (tfr_status) {
-- /*need to disable intr*/
-- iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
-- iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
-- pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
-- call_tasklet = 1;
-- }
-- err_status &= mid->intr_mask;
-- if (err_status) {
-- iowrite32((err_status << INT_MASK_WE),
-- mid->dma_base + MASK_ERR);
-- call_tasklet = 1;
-- }
-- if (call_tasklet)
-- tasklet_schedule(&mid->tasklet);
--
-- return IRQ_HANDLED;
--}
--
--static irqreturn_t intel_mid_dma_interrupt1(int irq, void *data)
--{
-- return intel_mid_dma_interrupt(irq, data);
--}
--
--static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
--{
-- return intel_mid_dma_interrupt(irq, data);
--}
--
--/**
-- * mid_setup_dma - Setup the DMA controller
-- * @pdev: Controller PCI device structure
-- *
-- * Initialize the DMA controller, channels, registers with DMA engine,
-- * ISR. Initialize DMA controller channels.
-- */
--static int mid_setup_dma(struct pci_dev *pdev)
--{
-- struct middma_device *dma = pci_get_drvdata(pdev);
-- int err, i;
--
-- /* DMA coherent memory pool for DMA descriptor allocations */
-- dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
-- sizeof(struct intel_mid_dma_desc),
-- 32, 0);
-- if (NULL == dma->dma_pool) {
-- pr_err("ERR_MDMA:pci_pool_create failed\n");
-- err = -ENOMEM;
-- goto err_dma_pool;
-- }
--
-- INIT_LIST_HEAD(&dma->common.channels);
-- dma->pci_id = pdev->device;
-- if (dma->pimr_mask) {
-- dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
-- LNW_PERIPHRAL_MASK_SIZE);
-- if (dma->mask_reg == NULL) {
-- pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
-- err = -ENOMEM;
-- goto err_ioremap;
-- }
-- } else
-- dma->mask_reg = NULL;
--
-- pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
-- /*init CH structures*/
-- dma->intr_mask = 0;
-- dma->state = RUNNING;
-- for (i = 0; i < dma->max_chan; i++) {
-- struct intel_mid_dma_chan *midch = &dma->ch[i];
--
-- midch->chan.device = &dma->common;
-- dma_cookie_init(&midch->chan);
-- midch->ch_id = dma->chan_base + i;
-- pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id);
--
-- midch->dma_base = dma->dma_base;
-- midch->ch_regs = dma->dma_base + DMA_CH_SIZE * midch->ch_id;
-- midch->dma = dma;
-- dma->intr_mask |= 1 << (dma->chan_base + i);
-- spin_lock_init(&midch->lock);
--
-- INIT_LIST_HEAD(&midch->active_list);
-- INIT_LIST_HEAD(&midch->queue);
-- INIT_LIST_HEAD(&midch->free_list);
-- /*mask interrupts*/
-- iowrite32(MASK_INTR_REG(midch->ch_id),
-- dma->dma_base + MASK_BLOCK);
-- iowrite32(MASK_INTR_REG(midch->ch_id),
-- dma->dma_base + MASK_SRC_TRAN);
-- iowrite32(MASK_INTR_REG(midch->ch_id),
-- dma->dma_base + MASK_DST_TRAN);
-- iowrite32(MASK_INTR_REG(midch->ch_id),
-- dma->dma_base + MASK_ERR);
-- iowrite32(MASK_INTR_REG(midch->ch_id),
-- dma->dma_base + MASK_TFR);
--
-- disable_dma_interrupt(midch);
-- list_add_tail(&midch->chan.device_node, &dma->common.channels);
-- }
-- pr_debug("MDMA: Calc Mask as %x for this controller\n", dma->intr_mask);
--
-- /*init dma structure*/
-- dma_cap_zero(dma->common.cap_mask);
-- dma_cap_set(DMA_MEMCPY, dma->common.cap_mask);
-- dma_cap_set(DMA_SLAVE, dma->common.cap_mask);
-- dma_cap_set(DMA_PRIVATE, dma->common.cap_mask);
-- dma->common.dev = &pdev->dev;
--
-- dma->common.device_alloc_chan_resources =
-- intel_mid_dma_alloc_chan_resources;
-- dma->common.device_free_chan_resources =
-- intel_mid_dma_free_chan_resources;
--
-- dma->common.device_tx_status = intel_mid_dma_tx_status;
-- dma->common.device_prep_dma_memcpy = intel_mid_dma_prep_memcpy;
-- dma->common.device_issue_pending = intel_mid_dma_issue_pending;
-- dma->common.device_prep_slave_sg = intel_mid_dma_prep_slave_sg;
-- dma->common.device_control = intel_mid_dma_device_control;
--
-- /*enable dma cntrl*/
-- iowrite32(REG_BIT0, dma->dma_base + DMA_CFG);
--
-- /*register irq */
-- if (dma->pimr_mask) {
-- pr_debug("MDMA:Requesting irq shared for DMAC1\n");
-- err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
-- IRQF_SHARED, "INTEL_MID_DMAC1", dma);
-- if (0 != err)
-- goto err_irq;
-- } else {
-- dma->intr_mask = 0x03;
-- pr_debug("MDMA:Requesting irq for DMAC2\n");
-- err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
-- IRQF_SHARED, "INTEL_MID_DMAC2", dma);
-- if (0 != err)
-- goto err_irq;
-- }
-- /*register device w/ engine*/
-- err = dma_async_device_register(&dma->common);
-- if (0 != err) {
-- pr_err("ERR_MDMA:device_register failed: %d\n", err);
-- goto err_engine;
-- }
-- if (dma->pimr_mask) {
-- pr_debug("setting up tasklet1 for DMAC1\n");
-- tasklet_init(&dma->tasklet, dma_tasklet1, (unsigned long)dma);
-- } else {
-- pr_debug("setting up tasklet2 for DMAC2\n");
-- tasklet_init(&dma->tasklet, dma_tasklet2, (unsigned long)dma);
-- }
-- return 0;
--
--err_engine:
-- free_irq(pdev->irq, dma);
--err_irq:
-- if (dma->mask_reg)
-- iounmap(dma->mask_reg);
--err_ioremap:
-- pci_pool_destroy(dma->dma_pool);
--err_dma_pool:
-- pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
-- return err;
--
--}
--
--/**
-- * middma_shutdown - Shutdown the DMA controller
-- * @pdev: Controller PCI device structure
-- *
-- * Called by remove
-- * Unregister DMa controller, clear all structures and free interrupt
-- */
--static void middma_shutdown(struct pci_dev *pdev)
--{
-- struct middma_device *device = pci_get_drvdata(pdev);
--
-- dma_async_device_unregister(&device->common);
-- pci_pool_destroy(device->dma_pool);
-- if (device->mask_reg)
-- iounmap(device->mask_reg);
-- if (device->dma_base)
-- iounmap(device->dma_base);
-- free_irq(pdev->irq, device);
-- return;
--}
--
--/**
-- * intel_mid_dma_probe - PCI Probe
-- * @pdev: Controller PCI device structure
-- * @id: pci device id structure
-- *
-- * Initialize the PCI device, map BARs, query driver data.
-- * Call setup_dma to complete contoller and chan initilzation
-- */
--static int intel_mid_dma_probe(struct pci_dev *pdev,
-- const struct pci_device_id *id)
--{
-- struct middma_device *device;
-- u32 base_addr, bar_size;
-- struct intel_mid_dma_probe_info *info;
-- int err;
--
-- pr_debug("MDMA: probe for %x\n", pdev->device);
-- info = (void *)id->driver_data;
-- pr_debug("MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
-- info->max_chan, info->ch_base,
-- info->block_size, info->pimr_mask);
--
-- err = pci_enable_device(pdev);
-- if (err)
-- goto err_enable_device;
--
-- err = pci_request_regions(pdev, "intel_mid_dmac");
-- if (err)
-- goto err_request_regions;
--
-- err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-- if (err)
-- goto err_set_dma_mask;
--
-- err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-- if (err)
-- goto err_set_dma_mask;
--
-- device = kzalloc(sizeof(*device), GFP_KERNEL);
-- if (!device) {
-- pr_err("ERR_MDMA:kzalloc failed probe\n");
-- err = -ENOMEM;
-- goto err_kzalloc;
-- }
-- device->pdev = pci_dev_get(pdev);
--
-- base_addr = pci_resource_start(pdev, 0);
-- bar_size = pci_resource_len(pdev, 0);
-- device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
-- if (!device->dma_base) {
-- pr_err("ERR_MDMA:ioremap failed\n");
-- err = -ENOMEM;
-- goto err_ioremap;
-- }
-- pci_set_drvdata(pdev, device);
-- pci_set_master(pdev);
-- device->max_chan = info->max_chan;
-- device->chan_base = info->ch_base;
-- device->block_size = info->block_size;
-- device->pimr_mask = info->pimr_mask;
--
-- err = mid_setup_dma(pdev);
-- if (err)
-- goto err_dma;
--
-- pm_runtime_put_noidle(&pdev->dev);
-- pm_runtime_allow(&pdev->dev);
-- return 0;
--
--err_dma:
-- iounmap(device->dma_base);
--err_ioremap:
-- pci_dev_put(pdev);
-- kfree(device);
--err_kzalloc:
--err_set_dma_mask:
-- pci_release_regions(pdev);
-- pci_disable_device(pdev);
--err_request_regions:
--err_enable_device:
-- pr_err("ERR_MDMA:Probe failed %d\n", err);
-- return err;
--}
--
--/**
-- * intel_mid_dma_remove - PCI remove
-- * @pdev: Controller PCI device structure
-- *
-- * Free up all resources and data
-- * Call shutdown_dma to complete contoller and chan cleanup
-- */
--static void intel_mid_dma_remove(struct pci_dev *pdev)
--{
-- struct middma_device *device = pci_get_drvdata(pdev);
--
-- pm_runtime_get_noresume(&pdev->dev);
-- pm_runtime_forbid(&pdev->dev);
-- middma_shutdown(pdev);
-- pci_dev_put(pdev);
-- kfree(device);
-- pci_release_regions(pdev);
-- pci_disable_device(pdev);
--}
--
--/* Power Management */
--/*
--* dma_suspend - PCI suspend function
--*
--* @pci: PCI device structure
--* @state: PM message
--*
--* This function is called by OS when a power event occurs
--*/
--static int dma_suspend(struct device *dev)
--{
-- struct pci_dev *pci = to_pci_dev(dev);
-- int i;
-- struct middma_device *device = pci_get_drvdata(pci);
-- pr_debug("MDMA: dma_suspend called\n");
--
-- for (i = 0; i < device->max_chan; i++) {
-- if (device->ch[i].in_use)
-- return -EAGAIN;
-- }
-- dmac1_mask_periphral_intr(device);
-- device->state = SUSPENDED;
-- pci_save_state(pci);
-- pci_disable_device(pci);
-- pci_set_power_state(pci, PCI_D3hot);
-- return 0;
--}
--
--/**
--* dma_resume - PCI resume function
--*
--* @pci: PCI device structure
--*
--* This function is called by OS when a power event occurs
--*/
--int dma_resume(struct device *dev)
--{
-- struct pci_dev *pci = to_pci_dev(dev);
-- int ret;
-- struct middma_device *device = pci_get_drvdata(pci);
--
-- pr_debug("MDMA: dma_resume called\n");
-- pci_set_power_state(pci, PCI_D0);
-- pci_restore_state(pci);
-- ret = pci_enable_device(pci);
-- if (ret) {
-- pr_err("MDMA: device can't be enabled for %x\n", pci->device);
-- return ret;
-- }
-- device->state = RUNNING;
-- iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-- return 0;
--}
--
--static int dma_runtime_suspend(struct device *dev)
--{
-- struct pci_dev *pci_dev = to_pci_dev(dev);
-- struct middma_device *device = pci_get_drvdata(pci_dev);
--
-- device->state = SUSPENDED;
-- return 0;
--}
--
--static int dma_runtime_resume(struct device *dev)
--{
-- struct pci_dev *pci_dev = to_pci_dev(dev);
-- struct middma_device *device = pci_get_drvdata(pci_dev);
--
-- device->state = RUNNING;
-- iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-- return 0;
--}
--
--static int dma_runtime_idle(struct device *dev)
--{
-- struct pci_dev *pdev = to_pci_dev(dev);
-- struct middma_device *device = pci_get_drvdata(pdev);
-- int i;
--
-- for (i = 0; i < device->max_chan; i++) {
-- if (device->ch[i].in_use)
-- return -EAGAIN;
-- }
--
-- return pm_schedule_suspend(dev, 0);
--}
--
--/******************************************************************************
--* PCI stuff
--*/
--static struct pci_device_id intel_mid_dma_ids[] = {
-- { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
-- { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
-- { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
-- { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
-- { 0, }
--};
--MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
--
--static const struct dev_pm_ops intel_mid_dma_pm = {
-- .runtime_suspend = dma_runtime_suspend,
-- .runtime_resume = dma_runtime_resume,
-- .runtime_idle = dma_runtime_idle,
-- .suspend = dma_suspend,
-- .resume = dma_resume,
--};
--
--static struct pci_driver intel_mid_dma_pci_driver = {
-- .name = "Intel MID DMA",
-- .id_table = intel_mid_dma_ids,
-- .probe = intel_mid_dma_probe,
-- .remove = intel_mid_dma_remove,
--#ifdef CONFIG_PM
-- .driver = {
-- .pm = &intel_mid_dma_pm,
-- },
--#endif
--};
--
--static int __init intel_mid_dma_init(void)
--{
-- pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
-- INTEL_MID_DMA_DRIVER_VERSION);
-- return pci_register_driver(&intel_mid_dma_pci_driver);
--}
--fs_initcall(intel_mid_dma_init);
--
--static void __exit intel_mid_dma_exit(void)
--{
-- pci_unregister_driver(&intel_mid_dma_pci_driver);
--}
--module_exit(intel_mid_dma_exit);
--
--MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
--MODULE_DESCRIPTION("Intel (R) MID DMAC Driver");
--MODULE_LICENSE("GPL v2");
--MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
-diff --git a/drivers/dma/intel_mid_dma/Makefile b/drivers/dma/intel_mid_dma/Makefile
-new file mode 100644
-index 0000000..6b38f9f
---- /dev/null
-+++ b/drivers/dma/intel_mid_dma/Makefile
-@@ -0,0 +1,3 @@
-+obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
-+intel_mid_dma-objs:= intel_cln_dma_pci.o intel_mid_dma_pci.o
-+
-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
---- /dev/null
-+++ b/drivers/dma/intel_mid_dma_core.c
-@@ -0,0 +1,1295 @@
-+/*
-+ * intel_mid_dma_core.c - Intel Langwell DMA Drivers
-+ *
-+ * Copyright (C) 2008-14 Intel Corp
-+ * Author: Vinod Koul <vinod.koul@intel.com>
-+ * The driver design is based on dw_dmac driver
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-+ *
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ *
-+ *
-+ */
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/intel_mid_dma.h>
-+#include <linux/module.h>
-+
-+#include "dmaengine.h"
-+#include "intel_mid_dma_regs.h"
-+
-+#define MAX_CHAN 4 /*max ch across controllers*/
-+
-+#define INTEL_MID_DMAC1_ID 0x0814
-+#define INTEL_MID_DMAC2_ID 0x0813
-+#define INTEL_MID_GP_DMAC2_ID 0x0827
-+#define INTEL_MFLD_DMAC1_ID 0x0830
-+#define LNW_PERIPHRAL_MASK_BASE 0xFFAE8008
-+#define LNW_PERIPHRAL_MASK_SIZE 0x10
-+#define LNW_PERIPHRAL_STATUS 0x0
-+#define LNW_PERIPHRAL_MASK 0x8
-+
-+#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*/
-+/**
-+ * get_ch_index - convert status to channel
-+ * @status: status mask
-+ * @base: dma ch base value
-+ *
-+ * Modify the status mask and return the channel index needing
-+ * attention (or -1 if neither)
-+ */
-+static int get_ch_index(int *status, unsigned int base)
-+{
-+ int i;
-+ for (i = 0; i < MAX_CHAN; i++) {
-+ if (*status & (1 << (i + base))) {
-+ *status = *status & ~(1 << (i + base));
-+ pr_debug("MDMA: index %d New status %x\n", i, *status);
-+ return i;
-+ }
-+ }
-+ return -1;
-+}
-+
-+/**
-+ * get_block_ts - calculates dma transaction length
-+ * @len: dma transfer length
-+ * @tx_width: dma transfer src width
-+ * @block_size: dma controller max block size
-+ *
-+ * Based on src width calculate the DMA trsaction length in data items
-+ * return data items or FFFF if exceeds max length for block
-+ */
-+static int get_block_ts(int len, int tx_width, int block_size)
-+{
-+ int byte_width = 0, block_ts = 0;
-+
-+ switch (tx_width) {
-+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
-+ byte_width = 1;
-+ break;
-+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
-+ byte_width = 2;
-+ break;
-+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
-+ default:
-+ byte_width = 4;
-+ break;
-+ }
-+
-+ block_ts = len/byte_width;
-+ if (block_ts > block_size)
-+ block_ts = 0xFFFF;
-+ return block_ts;
-+}
-+
-+/*****************************************************************************
-+DMAC1 interrupt Functions*/
-+
-+/**
-+ * dmac1_mask_periphral_intr - mask the periphral interrupt
-+ * @mid: dma device for which masking is required
-+ *
-+ * Masks the DMA periphral interrupt
-+ * this is valid for DMAC1 family controllers only
-+ * This controller should have periphral mask registers already mapped
-+ */
-+void dmac1_mask_periphral_intr(struct middma_device *mid)
-+{
-+ u32 pimr;
-+
-+ if (mid->pimr_mask) {
-+ pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
-+ pimr |= mid->pimr_mask;
-+ writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
-+ }
-+ return;
-+}
-+
-+/**
-+ * dmac1_unmask_periphral_intr - unmask the periphral interrupt
-+ * @midc: dma channel for which masking is required
-+ *
-+ * UnMasks the DMA periphral interrupt,
-+ * this is valid for DMAC1 family controllers only
-+ * This controller should have periphral mask registers already mapped
-+ */
-+void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc)
-+{
-+ u32 pimr;
-+ struct middma_device *mid = to_middma_device(midc->chan.device);
-+
-+ if (mid->pimr_mask) {
-+ pimr = readl(mid->mask_reg + LNW_PERIPHRAL_MASK);
-+ pimr &= ~mid->pimr_mask;
-+ writel(pimr, mid->mask_reg + LNW_PERIPHRAL_MASK);
-+ }
-+ return;
-+}
-+
-+/**
-+ * enable_dma_interrupt - enable the periphral interrupt
-+ * @midc: dma channel for which enable interrupt is required
-+ *
-+ * Enable the DMA periphral interrupt,
-+ * this is valid for DMAC1 family controllers only
-+ * This controller should have periphral mask registers already mapped
-+ */
-+static void enable_dma_interrupt(struct intel_mid_dma_chan *midc)
-+{
-+ dmac1_unmask_periphral_intr(midc);
-+
-+ /*en ch interrupts*/
-+ iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
-+ iowrite32(UNMASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
-+ return;
-+}
-+
-+/**
-+ * disable_dma_interrupt - disable the periphral interrupt
-+ * @midc: dma channel for which disable interrupt is required
-+ *
-+ * Disable the DMA periphral interrupt,
-+ * this is valid for DMAC1 family controllers only
-+ * This controller should have periphral mask registers already mapped
-+ */
-+static void disable_dma_interrupt(struct intel_mid_dma_chan *midc)
-+{
-+ /*Check LPE PISR, make sure fwd is disabled*/
-+ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_BLOCK);
-+ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_TFR);
-+ iowrite32(MASK_INTR_REG(midc->ch_id), midc->dma_base + MASK_ERR);
-+ return;
-+}
-+
-+/*****************************************************************************
-+DMA channel helper Functions*/
-+/**
-+ * mid_desc_get - get a descriptor
-+ * @midc: dma channel for which descriptor is required
-+ *
-+ * Obtain a descriptor for the channel. Returns NULL if none are free.
-+ * Once the descriptor is returned it is private until put on another
-+ * list or freed
-+ */
-+static struct intel_mid_dma_desc *midc_desc_get(struct intel_mid_dma_chan *midc)
-+{
-+ struct intel_mid_dma_desc *desc, *_desc;
-+ struct intel_mid_dma_desc *ret = NULL;
-+
-+ spin_lock_bh(&midc->lock);
-+ list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
-+ if (async_tx_test_ack(&desc->txd)) {
-+ list_del(&desc->desc_node);
-+ ret = desc;
-+ break;
-+ }
-+ }
-+ spin_unlock_bh(&midc->lock);
-+ return ret;
-+}
-+
-+/**
-+ * mid_desc_put - put a descriptor
-+ * @midc: dma channel for which descriptor is required
-+ * @desc: descriptor to put
-+ *
-+ * Return a descriptor from lwn_desc_get back to the free pool
-+ */
-+static void midc_desc_put(struct intel_mid_dma_chan *midc,
-+ struct intel_mid_dma_desc *desc)
-+{
-+ if (desc) {
-+ spin_lock_bh(&midc->lock);
-+ list_add_tail(&desc->desc_node, &midc->free_list);
-+ spin_unlock_bh(&midc->lock);
-+ }
-+}
-+/**
-+ * midc_dostart - begin a DMA transaction
-+ * @midc: channel for which txn is to be started
-+ * @first: first descriptor of series
-+ *
-+ * Load a transaction into the engine. This must be called with midc->lock
-+ * held and bh disabled.
-+ */
-+static void midc_dostart(struct intel_mid_dma_chan *midc,
-+ struct intel_mid_dma_desc *first)
-+{
-+ struct middma_device *mid = to_middma_device(midc->chan.device);
-+
-+ /* channel is idle */
-+ if (midc->busy && test_ch_en(midc->dma_base, midc->ch_id)) {
-+ /*error*/
-+ pr_err("ERR_MDMA: channel is busy in start\n");
-+ /* The tasklet will hopefully advance the queue... */
-+ return;
-+ }
-+ midc->busy = true;
-+ /*write registers and en*/
-+ iowrite32(first->sar, midc->ch_regs + SAR);
-+ iowrite32(first->dar, midc->ch_regs + DAR);
-+ iowrite32(first->lli_phys, midc->ch_regs + LLP);
-+ iowrite32(first->cfg_hi, midc->ch_regs + CFG_HIGH);
-+ iowrite32(first->cfg_lo, midc->ch_regs + CFG_LOW);
-+ iowrite32(first->ctl_lo, midc->ch_regs + CTL_LOW);
-+ iowrite32(first->ctl_hi, midc->ch_regs + CTL_HIGH);
-+ pr_debug("MDMA:TX SAR %x,DAR %x,CFGL %x,CFGH %x,CTLH %x, CTLL %x\n",
-+ (int)first->sar, (int)first->dar, first->cfg_hi,
-+ first->cfg_lo, first->ctl_hi, first->ctl_lo);
-+ first->status = DMA_IN_PROGRESS;
-+
-+ iowrite32(ENABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
-+}
-+
-+/**
-+ * midc_descriptor_complete - process completed descriptor
-+ * @midc: channel owning the descriptor
-+ * @desc: the descriptor itself
-+ *
-+ * Process a completed descriptor and perform any callbacks upon
-+ * the completion. The completion handling drops the lock during the
-+ * callbacks but must be called with the lock held.
-+ */
-+static void midc_descriptor_complete(struct intel_mid_dma_chan *midc,
-+ struct intel_mid_dma_desc *desc)
-+ __releases(&midc->lock) __acquires(&midc->lock)
-+{
-+ struct dma_async_tx_descriptor *txd = &desc->txd;
-+ dma_async_tx_callback callback_txd = NULL;
-+ struct intel_mid_dma_lli *llitem;
-+ void *param_txd = NULL;
-+
-+ 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;
-+ llitem->ctl_hi &= CLEAR_DONE;
-+ if (desc->current_lli < desc->lli_length-1)
-+ (desc->current_lli)++;
-+ else
-+ desc->current_lli = 0;
-+ }
-+ spin_unlock_bh(&midc->lock);
-+ if (callback_txd) {
-+ pr_debug("MDMA: TXD callback set ... calling\n");
-+ callback_txd(param_txd);
-+ }
-+ if (midc->raw_tfr) {
-+ desc->status = DMA_SUCCESS;
-+ if (desc->lli != NULL) {
-+ pci_pool_free(desc->lli_pool, desc->lli,
-+ desc->lli_phys);
-+ pci_pool_destroy(desc->lli_pool);
-+ desc->lli = NULL;
-+ }
-+ list_move(&desc->desc_node, &midc->free_list);
-+ midc->busy = false;
-+ }
-+ spin_lock_bh(&midc->lock);
-+
-+}
-+/**
-+ * midc_scan_descriptors - check the descriptors in channel
-+ * mark completed when tx is completete
-+ * @mid: device
-+ * @midc: channel to scan
-+ *
-+ * Walk the descriptor chain for the device and process any entries
-+ * that are complete.
-+ */
-+static void midc_scan_descriptors(struct middma_device *mid,
-+ struct intel_mid_dma_chan *midc)
-+{
-+ struct intel_mid_dma_desc *desc = NULL, *_desc = NULL;
-+
-+ /*tx is complete*/
-+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-+ if (desc->status == DMA_IN_PROGRESS)
-+ midc_descriptor_complete(midc, desc);
-+ }
-+ return;
-+ }
-+/**
-+ * midc_lli_fill_sg - Helper function to convert
-+ * SG list to Linked List Items.
-+ *@midc: Channel
-+ *@desc: DMA descriptor
-+ *@sglist: Pointer to SG list
-+ *@sglen: SG list length
-+ *@flags: DMA transaction flags
-+ *
-+ * Walk through the SG list and convert the SG list into Linked
-+ * List Items (LLI).
-+ */
-+static int midc_lli_fill_sg(struct intel_mid_dma_chan *midc,
-+ struct intel_mid_dma_desc *desc,
-+ struct scatterlist *sglist,
-+ unsigned int sglen,
-+ unsigned int flags)
-+{
-+ struct intel_mid_dma_slave *mids;
-+ struct scatterlist *sg;
-+ dma_addr_t lli_next, sg_phy_addr;
-+ struct intel_mid_dma_lli *lli_bloc_desc;
-+ union intel_mid_dma_ctl_lo ctl_lo;
-+ union intel_mid_dma_ctl_hi ctl_hi;
-+ int i;
-+
-+ pr_debug("MDMA: Entered midc_lli_fill_sg\n");
-+ mids = midc->mid_slave;
-+
-+ lli_bloc_desc = desc->lli;
-+ lli_next = desc->lli_phys;
-+
-+ ctl_lo.ctl_lo = desc->ctl_lo;
-+ ctl_hi.ctl_hi = desc->ctl_hi;
-+ for_each_sg(sglist, sg, sglen, i) {
-+ /*Populate CTL_LOW and LLI values*/
-+ if (i != sglen - 1) {
-+ lli_next = lli_next +
-+ sizeof(struct intel_mid_dma_lli);
-+ } else {
-+ /*Check for circular list, otherwise terminate LLI to ZERO*/
-+ if (flags & DMA_PREP_CIRCULAR_LIST) {
-+ pr_debug("MDMA: LLI is configured in circular mode\n");
-+ lli_next = desc->lli_phys;
-+ } else {
-+ lli_next = 0;
-+ ctl_lo.ctlx.llp_dst_en = 0;
-+ ctl_lo.ctlx.llp_src_en = 0;
-+ }
-+ }
-+ /*Populate CTL_HI values*/
-+ ctl_hi.ctlx.block_ts = get_block_ts(sg_dma_len(sg),
-+ desc->width,
-+ midc->dma->block_size);
-+ /*Populate SAR and DAR values*/
-+ sg_phy_addr = sg_dma_address(sg);
-+ if (desc->dirn == DMA_MEM_TO_DEV) {
-+ lli_bloc_desc->sar = sg_phy_addr;
-+ lli_bloc_desc->dar = mids->dma_slave.dst_addr;
-+ } else if (desc->dirn == DMA_DEV_TO_MEM) {
-+ lli_bloc_desc->sar = mids->dma_slave.src_addr;
-+ lli_bloc_desc->dar = sg_phy_addr;
-+ }
-+ /*Copy values into block descriptor in system memroy*/
-+ lli_bloc_desc->llp = lli_next;
-+ lli_bloc_desc->ctl_lo = ctl_lo.ctl_lo;
-+ lli_bloc_desc->ctl_hi = ctl_hi.ctl_hi;
-+
-+ lli_bloc_desc++;
-+ }
-+ /*Copy very first LLI values to descriptor*/
-+ desc->ctl_lo = desc->lli->ctl_lo;
-+ desc->ctl_hi = desc->lli->ctl_hi;
-+ desc->sar = desc->lli->sar;
-+ desc->dar = desc->lli->dar;
-+
-+ return 0;
-+}
-+/*****************************************************************************
-+DMA engine callback Functions*/
-+/**
-+ * intel_mid_dma_tx_submit - callback to submit DMA transaction
-+ * @tx: dma engine descriptor
-+ *
-+ * Submit the DMA transaction for this descriptor, start if ch idle
-+ */
-+static dma_cookie_t intel_mid_dma_tx_submit(struct dma_async_tx_descriptor *tx)
-+{
-+ struct intel_mid_dma_desc *desc = to_intel_mid_dma_desc(tx);
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(tx->chan);
-+ dma_cookie_t cookie;
-+
-+ spin_lock_bh(&midc->lock);
-+ cookie = dma_cookie_assign(tx);
-+
-+ if (list_empty(&midc->active_list))
-+ list_add_tail(&desc->desc_node, &midc->active_list);
-+ else
-+ list_add_tail(&desc->desc_node, &midc->queue);
-+
-+ midc_dostart(midc, desc);
-+ spin_unlock_bh(&midc->lock);
-+
-+ return cookie;
-+}
-+
-+/**
-+ * intel_mid_dma_issue_pending - callback to issue pending txn
-+ * @chan: chan where pending trascation needs to be checked and submitted
-+ *
-+ * Call for scan to issue pending descriptors
-+ */
-+static void intel_mid_dma_issue_pending(struct dma_chan *chan)
-+{
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-+
-+ spin_lock_bh(&midc->lock);
-+ if (!list_empty(&midc->queue))
-+ midc_scan_descriptors(to_middma_device(chan->device), midc);
-+ spin_unlock_bh(&midc->lock);
-+}
-+
-+/**
-+ * intel_mid_dma_tx_status - Return status of txn
-+ * @chan: chan for where status needs to be checked
-+ * @cookie: cookie for txn
-+ * @txstate: DMA txn state
-+ *
-+ * Return status of DMA txn
-+ */
-+static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
-+ dma_cookie_t cookie,
-+ struct dma_tx_state *txstate)
-+{
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-+ enum dma_status ret;
-+
-+ ret = dma_cookie_status(chan, cookie, txstate);
-+ if (ret != DMA_SUCCESS) {
-+ spin_lock_bh(&midc->lock);
-+ midc_scan_descriptors(to_middma_device(chan->device), midc);
-+ spin_unlock_bh(&midc->lock);
-+
-+ ret = dma_cookie_status(chan, cookie, txstate);
-+ }
-+
-+ return ret;
-+}
-+
-+static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
-+{
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-+ struct dma_slave_config *slave = (struct dma_slave_config *)arg;
-+ struct intel_mid_dma_slave *mid_slave;
-+
-+ BUG_ON(!midc);
-+ BUG_ON(!slave);
-+ pr_debug("MDMA: slave control called\n");
-+
-+ mid_slave = to_intel_mid_dma_slave(slave);
-+
-+ BUG_ON(!mid_slave);
-+
-+ midc->mid_slave = mid_slave;
-+ return 0;
-+}
-+/**
-+ * intel_mid_dma_device_control - DMA device control
-+ * @chan: chan for DMA control
-+ * @cmd: control cmd
-+ * @arg: cmd arg value
-+ *
-+ * Perform DMA control command
-+ */
-+static int intel_mid_dma_device_control(struct dma_chan *chan,
-+ enum dma_ctrl_cmd cmd, unsigned long arg)
-+{
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-+ struct middma_device *mid = to_middma_device(chan->device);
-+ struct intel_mid_dma_desc *desc, *_desc;
-+ union intel_mid_dma_cfg_lo cfg_lo;
-+
-+ if (cmd == DMA_SLAVE_CONFIG)
-+ return dma_slave_control(chan, arg);
-+
-+ if (cmd != DMA_TERMINATE_ALL)
-+ return -ENXIO;
-+
-+ spin_lock_bh(&midc->lock);
-+ if (midc->busy == false) {
-+ spin_unlock_bh(&midc->lock);
-+ return 0;
-+ }
-+ /*Suspend and disable the channel*/
-+ cfg_lo.cfg_lo = ioread32(midc->ch_regs + CFG_LOW);
-+ cfg_lo.cfgx.ch_susp = 1;
-+ iowrite32(cfg_lo.cfg_lo, midc->ch_regs + CFG_LOW);
-+ iowrite32(DISABLE_CHANNEL(midc->ch_id), mid->dma_base + DMA_CHAN_EN);
-+ midc->busy = false;
-+ /* Disable interrupts */
-+ disable_dma_interrupt(midc);
-+ midc->descs_allocated = 0;
-+
-+ spin_unlock_bh(&midc->lock);
-+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-+ if (desc->lli != NULL) {
-+ pci_pool_free(desc->lli_pool, desc->lli,
-+ desc->lli_phys);
-+ pci_pool_destroy(desc->lli_pool);
-+ desc->lli = NULL;
-+ }
-+ list_move(&desc->desc_node, &midc->free_list);
-+ }
-+ return 0;
-+}
-+
-+
-+/**
-+ * intel_mid_dma_prep_memcpy - Prep memcpy txn
-+ * @chan: chan for DMA transfer
-+ * @dest: destn address
-+ * @src: src address
-+ * @len: DMA transfer len
-+ * @flags: DMA flags
-+ *
-+ * Perform a DMA memcpy. Note we support slave periphral DMA transfers only
-+ * The periphral txn details should be filled in slave structure properly
-+ * Returns the descriptor for this txn
-+ */
-+static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy(
-+ struct dma_chan *chan, dma_addr_t dest,
-+ dma_addr_t src, size_t len, unsigned long flags)
-+{
-+ struct intel_mid_dma_chan *midc;
-+ struct intel_mid_dma_desc *desc = NULL;
-+ struct intel_mid_dma_slave *mids;
-+ union intel_mid_dma_ctl_lo ctl_lo;
-+ union intel_mid_dma_ctl_hi ctl_hi;
-+ union intel_mid_dma_cfg_lo cfg_lo;
-+ union intel_mid_dma_cfg_hi cfg_hi;
-+ enum dma_slave_buswidth width;
-+
-+ pr_debug("MDMA: Prep for memcpy\n");
-+ BUG_ON(!chan);
-+ if (!len)
-+ return NULL;
-+
-+ midc = to_intel_mid_dma_chan(chan);
-+ BUG_ON(!midc);
-+
-+ 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",
-+ mids->cfg_mode, mids->dma_slave.direction,
-+ mids->hs_mode, mids->dma_slave.src_addr_width);
-+
-+ /*calculate CFG_LO*/
-+ if (mids->hs_mode == LNW_DMA_SW_HS) {
-+ cfg_lo.cfg_lo = 0;
-+ cfg_lo.cfgx.hs_sel_dst = 1;
-+ cfg_lo.cfgx.hs_sel_src = 1;
-+ } else if (mids->hs_mode == LNW_DMA_HW_HS)
-+ cfg_lo.cfg_lo = 0x00000;
-+
-+ /*calculate CFG_HI*/
-+ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
-+ /*SW HS only*/
-+ cfg_hi.cfg_hi = 0;
-+ } else {
-+ cfg_hi.cfg_hi = 0;
-+ if (midc->dma->pimr_mask) {
-+ cfg_hi.cfgx.protctl = 0x0; /*default value*/
-+ cfg_hi.cfgx.fifo_mode = 1;
-+ if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
-+ cfg_hi.cfgx.src_per = 0;
-+ if (mids->device_instance == 0)
-+ cfg_hi.cfgx.dst_per = 3;
-+ if (mids->device_instance == 1)
-+ cfg_hi.cfgx.dst_per = 1;
-+ } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
-+ if (mids->device_instance == 0)
-+ cfg_hi.cfgx.src_per = 2;
-+ if (mids->device_instance == 1)
-+ cfg_hi.cfgx.src_per = 0;
-+ cfg_hi.cfgx.dst_per = 0;
-+ }
-+ } else {
-+ cfg_hi.cfgx.protctl = 0x1; /*default value*/
-+ cfg_hi.cfgx.src_per = cfg_hi.cfgx.dst_per =
-+ midc->ch_id - midc->dma->chan_base;
-+ }
-+ }
-+
-+ /*calculate CTL_HI*/
-+ ctl_hi.ctlx.reser = 0;
-+ ctl_hi.ctlx.done = 0;
-+ width = mids->dma_slave.src_addr_width;
-+
-+ ctl_hi.ctlx.block_ts = get_block_ts(len, width, midc->dma->block_size);
-+ pr_debug("MDMA:calc len %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;
-+
-+ /*
-+ * Here we need some translation from "enum dma_slave_buswidth"
-+ * to the format for our dma controller
-+ * standard intel_mid_dmac's format
-+ * 1 Byte 0b000
-+ * 2 Bytes 0b001
-+ * 4 Bytes 0b010
-+ */
-+ ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2;
-+ ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2;
-+
-+ if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) {
-+ ctl_lo.ctlx.tt_fc = 0;
-+ ctl_lo.ctlx.sinc = 0;
-+ ctl_lo.ctlx.dinc = 0;
-+ } else {
-+ if (mids->dma_slave.direction == DMA_MEM_TO_DEV) {
-+ ctl_lo.ctlx.sinc = 0;
-+ ctl_lo.ctlx.dinc = 2;
-+ ctl_lo.ctlx.tt_fc = 1;
-+ } else if (mids->dma_slave.direction == DMA_DEV_TO_MEM) {
-+ ctl_lo.ctlx.sinc = 2;
-+ ctl_lo.ctlx.dinc = 0;
-+ ctl_lo.ctlx.tt_fc = 2;
-+ }
-+ }
-+
-+ pr_debug("MDMA:Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n",
-+ ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi);
-+
-+ enable_dma_interrupt(midc);
-+
-+ desc = midc_desc_get(midc);
-+ if (desc == NULL)
-+ goto err_desc_get;
-+ desc->sar = src;
-+ desc->dar = dest ;
-+ desc->len = len;
-+ desc->cfg_hi = cfg_hi.cfg_hi;
-+ desc->cfg_lo = cfg_lo.cfg_lo;
-+ desc->ctl_lo = ctl_lo.ctl_lo;
-+ desc->ctl_hi = ctl_hi.ctl_hi;
-+ desc->width = width;
-+ desc->dirn = mids->dma_slave.direction;
-+ desc->lli_phys = 0;
-+ desc->lli = NULL;
-+ desc->lli_pool = NULL;
-+ return &desc->txd;
-+
-+err_desc_get:
-+ pr_err("ERR_MDMA: Failed to get desc\n");
-+ midc_desc_put(midc, desc);
-+ return NULL;
-+}
-+/**
-+ * intel_mid_dma_prep_slave_sg - Prep slave sg txn
-+ * @chan: chan for DMA transfer
-+ * @sgl: scatter gather list
-+ * @sg_len: length of sg txn
-+ * @direction: DMA transfer dirtn
-+ * @flags: DMA flags
-+ * @context: transfer context (ignored)
-+ *
-+ * Prepares LLI based periphral transfer
-+ */
-+static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg(
-+ struct dma_chan *chan, struct scatterlist *sgl,
-+ unsigned int sg_len, enum dma_transfer_direction direction,
-+ unsigned long flags, void *context)
-+{
-+ struct intel_mid_dma_chan *midc = NULL;
-+ struct intel_mid_dma_slave *mids = NULL;
-+ struct intel_mid_dma_desc *desc = NULL;
-+ struct dma_async_tx_descriptor *txd = NULL;
-+ union intel_mid_dma_ctl_lo ctl_lo;
-+
-+ pr_debug("MDMA: Prep for slave SG\n");
-+
-+ if (!sg_len) {
-+ pr_err("MDMA: Invalid SG length\n");
-+ return NULL;
-+ }
-+ midc = to_intel_mid_dma_chan(chan);
-+ BUG_ON(!midc);
-+
-+ mids = midc->mid_slave;
-+ BUG_ON(!mids);
-+
-+ if (!midc->dma->pimr_mask) {
-+ /* We can still handle sg list with only one item */
-+ if (sg_len == 1) {
-+ txd = intel_mid_dma_prep_memcpy(chan,
-+ mids->dma_slave.dst_addr,
-+ mids->dma_slave.src_addr,
-+ sg_dma_len(sgl),
-+ flags);
-+ return txd;
-+ } else {
-+ pr_warn("MDMA: SG list is not supported by this controller\n");
-+ return NULL;
-+ }
-+ }
-+
-+ pr_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);
-+ if (NULL == txd) {
-+ pr_err("MDMA: Prep memcpy failed\n");
-+ return NULL;
-+ }
-+
-+ desc = to_intel_mid_dma_desc(txd);
-+ desc->dirn = direction;
-+ ctl_lo.ctl_lo = desc->ctl_lo;
-+ ctl_lo.ctlx.llp_dst_en = 1;
-+ ctl_lo.ctlx.llp_src_en = 1;
-+ desc->ctl_lo = ctl_lo.ctl_lo;
-+ desc->lli_length = sg_len;
-+ desc->current_lli = 0;
-+ /* DMA coherent memory pool for LLI descriptors*/
-+ desc->lli_pool = pci_pool_create("intel_mid_dma_lli_pool",
-+ midc->dma->pdev,
-+ (sizeof(struct intel_mid_dma_lli)*sg_len),
-+ 32, 0);
-+ if (NULL == desc->lli_pool) {
-+ pr_err("MID_DMA:LLI pool create failed\n");
-+ return NULL;
-+ }
-+
-+ desc->lli = pci_pool_alloc(desc->lli_pool, GFP_KERNEL, &desc->lli_phys);
-+ if (!desc->lli) {
-+ pr_err("MID_DMA: LLI alloc failed\n");
-+ pci_pool_destroy(desc->lli_pool);
-+ return NULL;
-+ }
-+
-+ midc_lli_fill_sg(midc, desc, sgl, sg_len, flags);
-+ if (flags & DMA_PREP_INTERRUPT) {
-+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
-+ midc->dma_base + MASK_BLOCK);
-+ pr_debug("MDMA:Enabled Block interrupt\n");
-+ }
-+ return &desc->txd;
-+}
-+
-+/**
-+ * intel_mid_dma_free_chan_resources - Frees dma resources
-+ * @chan: chan requiring attention
-+ *
-+ * Frees the allocated resources on this DMA chan
-+ */
-+static void intel_mid_dma_free_chan_resources(struct dma_chan *chan)
-+{
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-+ struct middma_device *mid = to_middma_device(chan->device);
-+ struct intel_mid_dma_desc *desc, *_desc;
-+
-+ if (true == midc->busy) {
-+ /*trying to free ch in use!!!!!*/
-+ pr_err("ERR_MDMA: trying to free ch in use\n");
-+ }
-+ spin_lock_bh(&midc->lock);
-+ midc->descs_allocated = 0;
-+ list_for_each_entry_safe(desc, _desc, &midc->active_list, desc_node) {
-+ list_del(&desc->desc_node);
-+ pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
-+ }
-+ list_for_each_entry_safe(desc, _desc, &midc->free_list, desc_node) {
-+ list_del(&desc->desc_node);
-+ pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
-+ }
-+ list_for_each_entry_safe(desc, _desc, &midc->queue, desc_node) {
-+ list_del(&desc->desc_node);
-+ pci_pool_free(mid->dma_pool, desc, desc->txd.phys);
-+ }
-+ spin_unlock_bh(&midc->lock);
-+ midc->in_use = false;
-+ midc->busy = false;
-+ /* Disable CH interrupts */
-+ iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_BLOCK);
-+ iowrite32(MASK_INTR_REG(midc->ch_id), mid->dma_base + MASK_ERR);
-+ pm_runtime_put(&mid->pdev->dev);
-+}
-+
-+/**
-+ * intel_mid_dma_alloc_chan_resources - Allocate dma resources
-+ * @chan: chan requiring attention
-+ *
-+ * Allocates DMA resources on this chan
-+ * Return the descriptors allocated
-+ */
-+static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan)
-+{
-+ struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
-+ struct middma_device *mid = to_middma_device(chan->device);
-+ struct intel_mid_dma_desc *desc;
-+ dma_addr_t phys;
-+ int i = 0;
-+
-+ pm_runtime_get_sync(&mid->pdev->dev);
-+
-+ if (mid->state == SUSPENDED) {
-+ if (dma_resume(&mid->pdev->dev)) {
-+ pr_err("ERR_MDMA: resume failed");
-+ return -EFAULT;
-+ }
-+ }
-+
-+ /* ASSERT: channel is idle */
-+ if (test_ch_en(mid->dma_base, midc->ch_id)) {
-+ /*ch is not idle*/
-+ pr_err("ERR_MDMA: ch not idle\n");
-+ pm_runtime_put(&mid->pdev->dev);
-+ return -EIO;
-+ }
-+ dma_cookie_init(chan);
-+
-+ spin_lock_bh(&midc->lock);
-+ while (midc->descs_allocated < DESCS_PER_CHANNEL) {
-+ spin_unlock_bh(&midc->lock);
-+ desc = pci_pool_alloc(mid->dma_pool, GFP_KERNEL, &phys);
-+ if (!desc) {
-+ pr_err("ERR_MDMA: desc failed\n");
-+ pm_runtime_put(&mid->pdev->dev);
-+ return -ENOMEM;
-+ /*check*/
-+ }
-+ dma_async_tx_descriptor_init(&desc->txd, chan);
-+ desc->txd.tx_submit = intel_mid_dma_tx_submit;
-+ desc->txd.flags = DMA_CTRL_ACK;
-+ desc->txd.phys = phys;
-+ spin_lock_bh(&midc->lock);
-+ i = ++midc->descs_allocated;
-+ list_add_tail(&desc->desc_node, &midc->free_list);
-+ }
-+ spin_unlock_bh(&midc->lock);
-+ midc->in_use = true;
-+ midc->busy = false;
-+ pr_debug("MID_DMA: Desc alloc done ret: %d desc\n", i);
-+ return i;
-+}
-+
-+/**
-+ * midc_handle_error - Handle DMA txn error
-+ * @mid: controller where error occurred
-+ * @midc: chan where error occurred
-+ *
-+ * Scan the descriptor for error
-+ */
-+static void midc_handle_error(struct middma_device *mid,
-+ struct intel_mid_dma_chan *midc)
-+{
-+ midc_scan_descriptors(mid, midc);
-+}
-+
-+/**
-+ * dma_tasklet - DMA interrupt tasklet
-+ * @data: tasklet arg (the controller structure)
-+ *
-+ * Scan the controller for interrupts for completion/error
-+ * Clear the interrupt and call for handling completion/error
-+ */
-+static void dma_tasklet(unsigned long data)
-+{
-+ struct middma_device *mid = NULL;
-+ struct intel_mid_dma_chan *midc = NULL;
-+ u32 status, raw_tfr, raw_block;
-+ int i;
-+
-+ mid = (struct middma_device *)data;
-+ if (mid == NULL) {
-+ pr_err("ERR_MDMA: tasklet Null param\n");
-+ return;
-+ }
-+ pr_debug("MDMA: in tasklet for device %x\n", mid->pci_id);
-+ raw_tfr = ioread32(mid->dma_base + RAW_TFR);
-+ raw_block = ioread32(mid->dma_base + RAW_BLOCK);
-+ status = raw_tfr | raw_block;
-+ status &= mid->intr_mask;
-+ while (status) {
-+ /*txn interrupt*/
-+ i = get_ch_index(&status, mid->chan_base);
-+ if (i < 0) {
-+ pr_err("ERR_MDMA:Invalid ch index %x\n", i);
-+ return;
-+ }
-+ midc = &mid->ch[i];
-+ if (midc == NULL) {
-+ pr_err("ERR_MDMA:Null param midc\n");
-+ return;
-+ }
-+ pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
-+ status, midc->ch_id, i);
-+ midc->raw_tfr = raw_tfr;
-+ midc->raw_block = raw_block;
-+ spin_lock_bh(&midc->lock);
-+ /*clearing this interrupts first*/
-+ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_TFR);
-+ if (raw_block) {
-+ iowrite32((1 << midc->ch_id),
-+ mid->dma_base + CLEAR_BLOCK);
-+ }
-+ midc_scan_descriptors(mid, midc);
-+ pr_debug("MDMA:Scan of desc... complete, unmasking\n");
-+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
-+ mid->dma_base + MASK_TFR);
-+ if (raw_block) {
-+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
-+ mid->dma_base + MASK_BLOCK);
-+ }
-+ spin_unlock_bh(&midc->lock);
-+ }
-+
-+ status = ioread32(mid->dma_base + RAW_ERR);
-+ status &= mid->intr_mask;
-+ while (status) {
-+ /*err interrupt*/
-+ i = get_ch_index(&status, mid->chan_base);
-+ if (i < 0) {
-+ pr_err("ERR_MDMA:Invalid ch index %x\n", i);
-+ return;
-+ }
-+ midc = &mid->ch[i];
-+ if (midc == NULL) {
-+ pr_err("ERR_MDMA:Null param midc\n");
-+ return;
-+ }
-+ pr_debug("MDMA:Tx complete interrupt %x, Ch No %d Index %d\n",
-+ status, midc->ch_id, i);
-+
-+ iowrite32((1 << midc->ch_id), mid->dma_base + CLEAR_ERR);
-+ spin_lock_bh(&midc->lock);
-+ midc_handle_error(mid, midc);
-+ iowrite32(UNMASK_INTR_REG(midc->ch_id),
-+ mid->dma_base + MASK_ERR);
-+ spin_unlock_bh(&midc->lock);
-+ }
-+ pr_debug("MDMA:Exiting takslet...\n");
-+ return;
-+}
-+
-+static void dma_tasklet1(unsigned long data)
-+{
-+ pr_debug("MDMA:in takslet1...\n");
-+ return dma_tasklet(data);
-+}
-+
-+static void dma_tasklet2(unsigned long data)
-+{
-+ pr_debug("MDMA:in takslet2...\n");
-+ return dma_tasklet(data);
-+}
-+
-+/**
-+ * intel_mid_dma_interrupt - DMA ISR
-+ * @irq: IRQ where interrupt occurred
-+ * @data: ISR cllback data (the controller structure)
-+ *
-+ * See if this is our interrupt if so then schedule the tasklet
-+ * otherwise ignore
-+ */
-+irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
-+{
-+ struct middma_device *mid = data;
-+ u32 tfr_status, err_status;
-+ int call_tasklet = 0;
-+
-+ tfr_status = ioread32(mid->dma_base + RAW_TFR);
-+ err_status = ioread32(mid->dma_base + RAW_ERR);
-+ if (!tfr_status && !err_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);
-+
-+#endif
-+ tfr_status &= mid->intr_mask;
-+ if (tfr_status) {
-+ /*need to disable intr*/
-+ iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_TFR);
-+ iowrite32((tfr_status << INT_MASK_WE), mid->dma_base + MASK_BLOCK);
-+ pr_debug("MDMA: Calling tasklet %x\n", tfr_status);
-+ call_tasklet = 1;
-+ }
-+ err_status &= mid->intr_mask;
-+ if (err_status) {
-+ iowrite32((err_status << INT_MASK_WE),
-+ mid->dma_base + MASK_ERR);
-+ call_tasklet = 1;
-+ }
-+ if (call_tasklet)
-+ tasklet_schedule(&mid->tasklet);
-+
-+ return IRQ_HANDLED;
-+}
-+EXPORT_SYMBOL(intel_mid_dma_interrupt);
-+
-+static irqreturn_t intel_mid_dma_interrupt1(int irq, void *data)
-+{
-+ return intel_mid_dma_interrupt(irq, data);
-+}
-+
-+static irqreturn_t intel_mid_dma_interrupt2(int irq, void *data)
-+{
-+ return intel_mid_dma_interrupt(irq, data);
-+}
-+
-+/**
-+ * mid_setup_dma - Setup the DMA controller
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Initialize the DMA controller, channels, registers with DMA engine,
-+ * ISR. Initialize DMA controller channels.
-+ */
-+int mid_setup_dma(struct pci_dev *pdev, struct middma_device *dma)
-+{
-+ int err, i;
-+
-+ /* DMA coherent memory pool for DMA descriptor allocations */
-+ dma->dma_pool = pci_pool_create("intel_mid_dma_desc_pool", pdev,
-+ sizeof(struct intel_mid_dma_desc),
-+ 32, 0);
-+ if (NULL == dma->dma_pool) {
-+ pr_err("ERR_MDMA:pci_pool_create failed\n");
-+ err = -ENOMEM;
-+ goto err_dma_pool;
-+ }
-+
-+ INIT_LIST_HEAD(&dma->common.channels);
-+ dma->pci_id = pdev->device;
-+ if (dma->pimr_mask) {
-+ dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE,
-+ LNW_PERIPHRAL_MASK_SIZE);
-+ if (dma->mask_reg == NULL) {
-+ pr_err("ERR_MDMA:Can't map periphral intr space !!\n");
-+ err = -ENOMEM;
-+ goto err_ioremap;
-+ }
-+ } else
-+ dma->mask_reg = NULL;
-+
-+ pr_debug("MDMA:Adding %d channel for this controller\n", dma->max_chan);
-+ /*init CH structures*/
-+ dma->intr_mask = 0;
-+ dma->state = RUNNING;
-+ for (i = 0; i < dma->max_chan; i++) {
-+ struct intel_mid_dma_chan *midch = &dma->ch[i];
-+
-+ midch->chan.device = &dma->common;
-+ dma_cookie_init(&midch->chan);
-+ midch->ch_id = dma->chan_base + i;
-+ pr_debug("MDMA:Init CH %d, ID %d\n", i, midch->ch_id);
-+
-+ midch->dma_base = dma->dma_base;
-+ midch->ch_regs = dma->dma_base + DMA_CH_SIZE * midch->ch_id;
-+ midch->dma = dma;
-+ dma->intr_mask |= 1 << (dma->chan_base + i);
-+ spin_lock_init(&midch->lock);
-+
-+ INIT_LIST_HEAD(&midch->active_list);
-+ INIT_LIST_HEAD(&midch->queue);
-+ INIT_LIST_HEAD(&midch->free_list);
-+ /*mask interrupts*/
-+ iowrite32(MASK_INTR_REG(midch->ch_id),
-+ dma->dma_base + MASK_BLOCK);
-+ iowrite32(MASK_INTR_REG(midch->ch_id),
-+ dma->dma_base + MASK_SRC_TRAN);
-+ iowrite32(MASK_INTR_REG(midch->ch_id),
-+ dma->dma_base + MASK_DST_TRAN);
-+ iowrite32(MASK_INTR_REG(midch->ch_id),
-+ dma->dma_base + MASK_ERR);
-+ iowrite32(MASK_INTR_REG(midch->ch_id),
-+ dma->dma_base + MASK_TFR);
-+
-+ disable_dma_interrupt(midch);
-+ list_add_tail(&midch->chan.device_node, &dma->common.channels);
-+ }
-+ pr_debug("MDMA: Calc Mask as %x for this controller\n", dma->intr_mask);
-+
-+ /*init dma structure*/
-+ dma_cap_zero(dma->common.cap_mask);
-+ dma_cap_set(DMA_MEMCPY, dma->common.cap_mask);
-+ dma_cap_set(DMA_SLAVE, dma->common.cap_mask);
-+ dma_cap_set(DMA_PRIVATE, dma->common.cap_mask);
-+ dma->common.dev = &pdev->dev;
-+
-+ dma->common.device_alloc_chan_resources =
-+ intel_mid_dma_alloc_chan_resources;
-+ dma->common.device_free_chan_resources =
-+ intel_mid_dma_free_chan_resources;
-+
-+ dma->common.device_tx_status = intel_mid_dma_tx_status;
-+ dma->common.device_prep_dma_memcpy = intel_mid_dma_prep_memcpy;
-+ dma->common.device_issue_pending = intel_mid_dma_issue_pending;
-+ dma->common.device_prep_slave_sg = intel_mid_dma_prep_slave_sg;
-+ dma->common.device_control = intel_mid_dma_device_control;
-+
-+ /*enable dma cntrl*/
-+ iowrite32(REG_BIT0, dma->dma_base + DMA_CFG);
-+
-+ /*register irq */
-+ if (dma->pimr_mask) {
-+ pr_debug("MDMA:Requesting irq shared for DMAC1\n");
-+ err = request_irq(pdev->irq, intel_mid_dma_interrupt1,
-+ IRQF_SHARED, "INTEL_MID_DMAC1", dma);
-+ if (0 != err)
-+ goto err_irq;
-+ } else {
-+ dma->intr_mask = 0x03;
-+ pr_debug("MDMA:Requesting irq for DMAC2\n");
-+ err = request_irq(pdev->irq, intel_mid_dma_interrupt2,
-+ IRQF_SHARED, "INTEL_MID_DMAC2", dma);
-+ if (0 != err)
-+ goto err_irq;
-+ }
-+ /*register device w/ engine*/
-+ err = dma_async_device_register(&dma->common);
-+ if (0 != err) {
-+ pr_err("ERR_MDMA:device_register failed: %d\n", err);
-+ goto err_engine;
-+ }
-+ if (dma->pimr_mask) {
-+ pr_debug("setting up tasklet1 for DMAC1\n");
-+ tasklet_init(&dma->tasklet, dma_tasklet1, (unsigned long)dma);
-+ } else {
-+ pr_debug("setting up tasklet2 for DMAC2\n");
-+ tasklet_init(&dma->tasklet, dma_tasklet2, (unsigned long)dma);
-+ }
-+ return 0;
-+
-+err_engine:
-+ free_irq(pdev->irq, dma);
-+err_irq:
-+ if (dma->mask_reg)
-+ iounmap(dma->mask_reg);
-+err_ioremap:
-+ pci_pool_destroy(dma->dma_pool);
-+err_dma_pool:
-+ pr_err("ERR_MDMA:setup_dma failed: %d\n", err);
-+ return err;
-+
-+}
-+/**
-+ * middma_shutdown - Shutdown the DMA controller
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Called by remove
-+ * Unregister DMa controller, clear all structures and free interrupt
-+ */
-+void middma_shutdown(struct pci_dev *pdev, struct middma_device *device)
-+{
-+ dma_async_device_unregister(&device->common);
-+ pci_pool_destroy(device->dma_pool);
-+ if (device->mask_reg)
-+ iounmap(device->mask_reg);
-+ if (device->dma_base)
-+ iounmap(device->dma_base);
-+ free_irq(pdev->irq, device);
-+ return;
-+}
-+
-+/* Power Management */
-+/*
-+* dma_suspend - PCI suspend function
-+*
-+* @pci: PCI device structure
-+* @state: PM message
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+static int dma_suspend(struct device *dev)
-+{
-+ struct pci_dev *pci = to_pci_dev(dev);
-+ int i;
-+ struct middma_device *device = pci_get_drvdata(pci);
-+ pr_debug("MDMA: dma_suspend called\n");
-+
-+ for (i = 0; i < device->max_chan; i++) {
-+ if (device->ch[i].in_use)
-+ return -EAGAIN;
-+ }
-+#if 0
-+ dmac1_mask_periphral_intr(device);
-+#endif
-+ device->state = SUSPENDED;
-+ pci_save_state(pci);
-+ pci_disable_device(pci);
-+ pci_set_power_state(pci, PCI_D3hot);
-+ return 0;
-+}
-+
-+/**
-+* dma_resume - PCI resume function
-+*
-+* @pci: PCI device structure
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+int middma_resume(struct device *dev)
-+{
-+ struct pci_dev *pci_dev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pci_dev);
-+
-+ device->state = RUNNING;
-+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-+ return 0;
-+}
-+
-+static int dma_runtime_suspend(struct device *dev)
-+{
-+ struct pci_dev *pci_dev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pci_dev);
-+
-+ device->state = SUSPENDED;
-+ return 0;
-+}
-+
-+static int dma_runtime_resume(struct device *dev)
-+{
-+ struct pci_dev *pci_dev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pci_dev);
-+
-+ device->state = RUNNING;
-+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-+ return 0;
-+}
-+
-+static int dma_runtime_idle(struct device *dev)
-+{
-+ struct pci_dev *pdev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pdev);
-+ int i;
-+
-+ for (i = 0; i < device->max_chan; i++) {
-+ if (device->ch[i].in_use)
-+ return -EAGAIN;
-+ }
-+
-+ return pm_schedule_suspend(dev, 0);
-+}
-+
-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
---- /dev/null
-+++ b/drivers/dma/intel_mid_dma_pci.c
-@@ -0,0 +1,290 @@
-+/*
-+ * intel_mid_dma.c - Intel Langwell DMA Drivers
-+ *
-+ * Copyright (C) 2008-12 Intel Corp
-+ * Author: Vinod Koul <vinod.koul@intel.com>
-+ * The driver design is based on dw_dmac driver
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License along
-+ * with this program; if not, write to the Free Software Foundation, Inc.,
-+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-+ *
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ *
-+ *
-+ */
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/intel_mid_dma.h>
-+#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) \
-+ ((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), \
-+ })
-+
-+/**
-+ * intel_mid_dma_probe - PCI Probe
-+ * @pdev: Controller PCI device structure
-+ * @id: pci device id structure
-+ *
-+ * Initialize the PCI device, map BARs, query driver data.
-+ * Call setup_dma to complete contoller and chan initilzation
-+ */
-+static int intel_mid_dma_probe(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
-+{
-+ struct middma_device *device;
-+ u32 base_addr, bar_size;
-+ struct intel_mid_dma_probe_info *info;
-+ int err;
-+
-+ pr_debug("MDMA: probe for %x\n", pdev->device);
-+ info = (void *)id->driver_data;
-+ pr_debug("MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
-+ info->max_chan, info->ch_base,
-+ info->block_size, info->pimr_mask);
-+
-+ err = pci_enable_device(pdev);
-+ if (err)
-+ goto err_enable_device;
-+
-+ err = pci_request_regions(pdev, "intel_mid_dmac");
-+ if (err)
-+ goto err_request_regions;
-+
-+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-+ if (err)
-+ goto err_set_dma_mask;
-+
-+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-+ if (err)
-+ goto err_set_dma_mask;
-+
-+ device = kzalloc(sizeof(*device), GFP_KERNEL);
-+ if (!device) {
-+ pr_err("ERR_MDMA:kzalloc failed probe\n");
-+ err = -ENOMEM;
-+ goto err_kzalloc;
-+ }
-+ device->pdev = pci_dev_get(pdev);
-+
-+ base_addr = pci_resource_start(pdev, 0);
-+ bar_size = pci_resource_len(pdev, 0);
-+ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
-+ if (!device->dma_base) {
-+ pr_err("ERR_MDMA:ioremap failed\n");
-+ err = -ENOMEM;
-+ goto err_ioremap;
-+ }
-+ pci_set_drvdata(pdev, device);
-+ pci_set_master(pdev);
-+ device->max_chan = info->max_chan;
-+ device->chan_base = info->ch_base;
-+ device->block_size = info->block_size;
-+ device->pimr_mask = info->pimr_mask;
-+
-+ err = mid_setup_dma(pdev, device);
-+ if (err)
-+ goto err_dma;
-+
-+ pm_runtime_put_noidle(&pdev->dev);
-+ pm_runtime_allow(&pdev->dev);
-+ return 0;
-+
-+err_dma:
-+ iounmap(device->dma_base);
-+err_ioremap:
-+ pci_dev_put(pdev);
-+ kfree(device);
-+err_kzalloc:
-+err_set_dma_mask:
-+ pci_release_regions(pdev);
-+ pci_disable_device(pdev);
-+err_request_regions:
-+err_enable_device:
-+ pr_err("ERR_MDMA:Probe failed %d\n", err);
-+ return err;
-+}
-+
-+/**
-+ * intel_mid_dma_remove - PCI remove
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Free up all resources and data
-+ * Call shutdown_dma to complete contoller and chan cleanup
-+ */
-+static void intel_mid_dma_remove(struct pci_dev *pdev)
-+{
-+ struct middma_device *device = pci_get_drvdata(pdev);
-+
-+ pm_runtime_get_noresume(&pdev->dev);
-+ pm_runtime_forbid(&pdev->dev);
-+#if 0
-+ middma_shutdown(pdev, device);
-+#endif
-+ pci_dev_put(pdev);
-+ kfree(device);
-+ pci_release_regions(pdev);
-+ pci_disable_device(pdev);
-+}
-+
-+/* Power Management */
-+/*
-+* dma_suspend - PCI suspend function
-+*
-+* @pci: PCI device structure
-+* @state: PM message
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+static int dma_suspend(struct device *dev)
-+{
-+ struct pci_dev *pci = to_pci_dev(dev);
-+ int i;
-+ struct middma_device *device = pci_get_drvdata(pci);
-+ pr_debug("MDMA: dma_suspend called\n");
-+
-+ for (i = 0; i < device->max_chan; i++) {
-+ if (device->ch[i].in_use)
-+ return -EAGAIN;
-+ }
-+#if 0
-+ dmac1_mask_periphral_intr(device);
-+#endif
-+ device->state = SUSPENDED;
-+ pci_save_state(pci);
-+ pci_disable_device(pci);
-+ pci_set_power_state(pci, PCI_D3hot);
-+ return 0;
-+}
-+
-+/**
-+* dma_resume - PCI resume function
-+*
-+* @pci: PCI device structure
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+int dma_resume(struct device *dev)
-+{
-+ struct pci_dev *pci = to_pci_dev(dev);
-+ int ret;
-+
-+ pr_debug("MDMA: dma_resume called\n");
-+ pci_set_power_state(pci, PCI_D0);
-+ pci_restore_state(pci);
-+ ret = pci_enable_device(pci);
-+ if (ret) {
-+ pr_err("MDMA: device can't be enabled for %x\n", pci->device);
-+ return ret;
-+ }
-+
-+ return middma_resume(dev);
-+}
-+
-+static int dma_runtime_suspend(struct device *dev)
-+{
-+ struct pci_dev *pci_dev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pci_dev);
-+
-+ device->state = SUSPENDED;
-+ return 0;
-+}
-+
-+static int dma_runtime_resume(struct device *dev)
-+{
-+ struct pci_dev *pci_dev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pci_dev);
-+
-+ device->state = RUNNING;
-+ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
-+ return 0;
-+}
-+
-+static int dma_runtime_idle(struct device *dev)
-+{
-+ struct pci_dev *pdev = to_pci_dev(dev);
-+ struct middma_device *device = pci_get_drvdata(pdev);
-+ int i;
-+
-+ for (i = 0; i < device->max_chan; i++) {
-+ if (device->ch[i].in_use)
-+ return -EAGAIN;
-+ }
-+
-+ return pm_schedule_suspend(dev, 0);
-+}
-+
-+/******************************************************************************
-+* PCI stuff
-+*/
-+static struct pci_device_id intel_mid_dma_ids[] = {
-+ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
-+ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
-+ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
-+ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
-+ { 0, }
-+};
-+MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
-+
-+static const struct dev_pm_ops intel_mid_dma_pm = {
-+ .runtime_suspend = dma_runtime_suspend,
-+ .runtime_resume = dma_runtime_resume,
-+ .runtime_idle = dma_runtime_idle,
-+ .suspend = dma_suspend,
-+ .resume = dma_resume,
-+};
-+
-+static struct pci_driver intel_mid_dma_pci_driver = {
-+ .name = "Intel MID DMA",
-+ .id_table = intel_mid_dma_ids,
-+ .probe = intel_mid_dma_probe,
-+ .remove = intel_mid_dma_remove,
-+#ifdef CONFIG_PM
-+ .driver = {
-+ .pm = &intel_mid_dma_pm,
-+ },
-+#endif
-+};
-+
-+static int __init intel_mid_dma_init(void)
-+{
-+ pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
-+ INTEL_MID_DMA_DRIVER_VERSION);
-+ return pci_register_driver(&intel_mid_dma_pci_driver);
-+}
-+fs_initcall(intel_mid_dma_init);
-+
-+static void __exit intel_mid_dma_exit(void)
-+{
-+ pci_unregister_driver(&intel_mid_dma_pci_driver);
-+}
-+module_exit(intel_mid_dma_exit);
-+
-+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
-+MODULE_DESCRIPTION("Intel (R) MID DMAC Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
-diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
-index 17b4219..4b2ba69 100644
---- a/drivers/dma/intel_mid_dma_regs.h
-+++ b/drivers/dma/intel_mid_dma_regs.h
-@@ -27,6 +27,7 @@
-
- #include <linux/dmaengine.h>
- #include <linux/dmapool.h>
-+#include <linux/intel_mid_dma.h>
- #include <linux/pci_ids.h>
-
- #define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
-@@ -158,115 +159,17 @@ union intel_mid_dma_cfg_hi {
- };
-
-
--/**
-- * struct intel_mid_dma_chan - internal mid representation of a DMA channel
-- * @chan: dma_chan strcture represetation for mid chan
-- * @ch_regs: MMIO register space pointer to channel register
-- * @dma_base: MMIO register space DMA engine base pointer
-- * @ch_id: DMA channel id
-- * @lock: channel spinlock
-- * @active_list: current active descriptors
-- * @queue: current queued up descriptors
-- * @free_list: current free descriptors
-- * @slave: dma slave structure
-- * @descs_allocated: total number of descriptors allocated
-- * @dma: dma device structure pointer
-- * @busy: bool representing if ch is busy (active txn) or not
-- * @in_use: bool representing if ch is in use or not
-- * @raw_tfr: raw trf interrupt received
-- * @raw_block: raw block interrupt received
-- */
--struct intel_mid_dma_chan {
-- struct dma_chan chan;
-- void __iomem *ch_regs;
-- void __iomem *dma_base;
-- int ch_id;
-- spinlock_t lock;
-- struct list_head active_list;
-- struct list_head queue;
-- struct list_head free_list;
-- unsigned int descs_allocated;
-- struct middma_device *dma;
-- bool busy;
-- bool in_use;
-- u32 raw_tfr;
-- u32 raw_block;
-- struct intel_mid_dma_slave *mid_slave;
--};
--
- static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
- struct dma_chan *chan)
- {
- return container_of(chan, struct intel_mid_dma_chan, chan);
- }
-
--enum intel_mid_dma_state {
-- RUNNING = 0,
-- SUSPENDED,
--};
--/**
-- * struct middma_device - internal representation of a DMA device
-- * @pdev: PCI device
-- * @dma_base: MMIO register space pointer of DMA
-- * @dma_pool: for allocating DMA descriptors
-- * @common: embedded struct dma_device
-- * @tasklet: dma tasklet for processing interrupts
-- * @ch: per channel data
-- * @pci_id: DMA device PCI ID
-- * @intr_mask: Interrupt mask to be used
-- * @mask_reg: MMIO register for periphral mask
-- * @chan_base: Base ch index (read from driver data)
-- * @max_chan: max number of chs supported (from drv_data)
-- * @block_size: Block size of DMA transfer supported (from drv_data)
-- * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
-- * @state: dma PM device state
-- */
--struct middma_device {
-- struct pci_dev *pdev;
-- void __iomem *dma_base;
-- struct pci_pool *dma_pool;
-- struct dma_device common;
-- struct tasklet_struct tasklet;
-- struct intel_mid_dma_chan ch[MAX_CHAN];
-- unsigned int pci_id;
-- unsigned int intr_mask;
-- void __iomem *mask_reg;
-- int chan_base;
-- int max_chan;
-- int block_size;
-- unsigned int pimr_mask;
-- enum intel_mid_dma_state state;
--};
--
- static inline struct middma_device *to_middma_device(struct dma_device *common)
- {
- return container_of(common, struct middma_device, common);
- }
-
--struct intel_mid_dma_desc {
-- void __iomem *block; /*ch ptr*/
-- struct list_head desc_node;
-- struct dma_async_tx_descriptor txd;
-- size_t len;
-- dma_addr_t sar;
-- dma_addr_t dar;
-- u32 cfg_hi;
-- u32 cfg_lo;
-- u32 ctl_lo;
-- u32 ctl_hi;
-- struct pci_pool *lli_pool;
-- struct intel_mid_dma_lli *lli;
-- dma_addr_t lli_phys;
-- unsigned int lli_length;
-- unsigned int current_lli;
-- dma_addr_t next;
-- enum dma_transfer_direction dirn;
-- enum dma_status status;
-- enum dma_slave_buswidth width; /*width of DMA txn*/
-- enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
--
--};
--
- 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
- }
-
-
-+int mid_setup_dma(struct pci_dev *pdev, struct middma_device *dma);
-+#if 0
-+void middma_shutdown(struct pci_dev *pdev, struct middma_device *device);
-+void dmac1_mask_periphral_intr(struct middma_device *mid);
-+void dmac1_unmask_periphral_intr(struct intel_mid_dma_chan *midc);
-+#endif
-+int middma_resume(struct device *dev);
-+
- int dma_resume(struct device *dev);
-
- #endif /*__INTEL_MID_DMAC_REGS_H__*/
-diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
-index 682de75..97e951b 100644
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -243,13 +243,14 @@ config GPIO_VR41XX
- Say yes here to support the NEC VR4100 series General-purpose I/O Uint
-
- config GPIO_SCH
-- tristate "Intel SCH/TunnelCreek/Centerton GPIO"
-+ tristate "Intel SCH/TunnelCreek/Centerton/Clanton GPIO"
- depends on PCI && X86
- select MFD_CORE
- select LPC_SCH
- help
- Say yes here to support GPIO interface on Intel Poulsbo SCH,
-- Intel Tunnel Creek processor or Intel Centerton processor.
-+ Intel Tunnel Creek processor, Intel Centerton processor or Intel
-+ Clanton.
- The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
- powered by the core power rail and are turned off during sleep
- modes (S3 and higher). The remaining four GPIOs are powered by
-@@ -261,6 +262,8 @@ config GPIO_SCH
- The Intel Centerton processor has a total of 30 GPIO pins.
- Twenty-one are powered by the core power rail and 9 from the
- suspend power supply.
-+ The Intel Clanton has 2 GPIOs powered by the core power well and 6
-+ form the suspend power well.
-
- config GPIO_ICH
- tristate "Intel ICH GPIO"
-diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
-index edae963..73591be 100644
---- a/drivers/gpio/gpio-sch.c
-+++ b/drivers/gpio/gpio-sch.c
-@@ -41,6 +41,13 @@ static DEFINE_SPINLOCK(gpio_lock);
-
- static unsigned short gpio_ba;
-
-+static void cln_gpio_restrict_release(struct device *dev) {}
-+static struct platform_device cln_gpio_restrict_pdev =
-+{
-+ .name = "cln-gpio-restrict-nc",
-+ .dev.release = cln_gpio_restrict_release,
-+};
-+
- static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
- {
- u8 curr_dirs;
-@@ -240,6 +247,14 @@ static int sch_gpio_probe(struct platform_device *pdev)
- sch_gpio_resume.ngpio = 9;
- break;
-
-+ case PCI_DEVICE_ID_INTEL_CLANTON_ILB:
-+ sch_gpio_core.base = 0;
-+ sch_gpio_core.ngpio = 2;
-+
-+ sch_gpio_resume.base = 2;
-+ sch_gpio_resume.ngpio = 6;
-+ break;
-+
- default:
- err = -ENODEV;
- goto err_sch_gpio_core;
-@@ -256,6 +271,10 @@ static int sch_gpio_probe(struct platform_device *pdev)
- if (err < 0)
- goto err_sch_gpio_resume;
-
-+ err = platform_device_register(&cln_gpio_restrict_pdev);
-+ if (err < 0)
-+ goto err_sch_gpio_resume;
-+
- return 0;
-
- err_sch_gpio_resume:
-@@ -277,6 +296,8 @@ static int sch_gpio_remove(struct platform_device *pdev)
- if (gpio_ba) {
- int err;
-
-+ platform_device_unregister(&cln_gpio_restrict_pdev);
-+
- err = gpiochip_remove(&sch_gpio_core);
- if (err)
- dev_err(&pdev->dev, "%s failed, %d\n",
-diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
-index 199fca1..5e897ff 100644
---- a/drivers/gpio/gpiolib.c
-+++ b/drivers/gpio/gpiolib.c
-@@ -60,11 +60,17 @@ struct gpio_desc {
- #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
- #define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
- #define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
-+#define FLAG_PULLUP 10 /* Gpio drive is resistive pullup */
-+#define FLAG_PULLDOWN 11 /* Gpio drive is resistive pulldown */
-+#define FLAG_STRONG 12 /* Gpio drive is strong (fast output) */
-+#define FLAG_HIZ 13 /* Gpio drive is Hi-Z (input) */
-
- #define ID_SHIFT 16 /* add new flags before this one */
-
- #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
- #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
-+#define GPIO_DRIVE_MASK (BIT(FLAG_PULLUP) | BIT(FLAG_PULLDOWN) \
-+ | BIT(FLAG_STRONG) | BIT(FLAG_HIZ))
-
- #ifdef CONFIG_DEBUG_FS
- const char *label;
-@@ -243,6 +249,10 @@ static DEFINE_MUTEX(sysfs_lock);
- * * is read/write as zero/nonzero
- * * also affects existing and subsequent "falling" and "rising"
- * /edge configuration
-+ * /drive
-+ * * sets signal drive mode
-+ * * is read/write as "pullup", "pulldown", "strong" or "hiz"
-+ *
- */
-
- static ssize_t gpio_direction_show(struct device *dev,
-@@ -573,9 +583,85 @@ static ssize_t gpio_active_low_store(struct device *dev,
- static const DEVICE_ATTR(active_low, 0644,
- gpio_active_low_show, gpio_active_low_store);
-
-+static ssize_t gpio_drive_show(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ const struct gpio_desc *desc = dev_get_drvdata(dev);
-+ ssize_t status;
-+
-+ mutex_lock(&sysfs_lock);
-+
-+ if (!test_bit(FLAG_EXPORT, &desc->flags)) {
-+ status = -EIO;
-+ } else {
-+ if (test_bit(FLAG_PULLUP, &desc->flags))
-+ status = sprintf(buf, "pullup\n");
-+ else if (test_bit(FLAG_PULLDOWN, &desc->flags))
-+ status = sprintf(buf, "pulldown\n");
-+ else if (test_bit(FLAG_STRONG, &desc->flags))
-+ status = sprintf(buf, "strong\n");
-+ else if (test_bit(FLAG_HIZ, &desc->flags))
-+ status = sprintf(buf, "hiz\n");
-+ else
-+ status = -EINVAL;
-+ }
-+
-+ mutex_unlock(&sysfs_lock);
-+ return status;
-+}
-+
-+static ssize_t gpio_drive_store(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t size)
-+{
-+ struct gpio_desc *desc = dev_get_drvdata(dev);
-+ unsigned gpio = desc - gpio_desc;
-+ ssize_t status;
-+
-+ mutex_lock(&sysfs_lock);
-+
-+ if (!test_bit(FLAG_EXPORT, &desc->flags))
-+ status = -EIO;
-+ else {
-+ if (sysfs_streq(buf, "pullup")) {
-+ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLUP);
-+ if (!status) {
-+ desc->flags &= ~GPIO_DRIVE_MASK;
-+ set_bit(FLAG_PULLUP, &desc->flags);
-+ }
-+ } else if (sysfs_streq(buf, "pulldown")) {
-+ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLDOWN);
-+ if (!status) {
-+ desc->flags &= ~GPIO_DRIVE_MASK;
-+ set_bit(FLAG_PULLDOWN, &desc->flags);
-+ }
-+ } else if (sysfs_streq(buf, "strong")) {
-+ status = gpio_set_drive(gpio, GPIOF_DRIVE_STRONG);
-+ if (!status) {
-+ desc->flags &= ~GPIO_DRIVE_MASK;
-+ set_bit(FLAG_STRONG, &desc->flags);
-+ }
-+ } else if (sysfs_streq(buf, "hiz")) {
-+ status = gpio_set_drive(gpio, GPIOF_DRIVE_HIZ);
-+ if (!status) {
-+ desc->flags &= ~GPIO_DRIVE_MASK;
-+ set_bit(FLAG_HIZ, &desc->flags);
-+ }
-+ } else {
-+ status = -EINVAL;
-+ }
-+ }
-+
-+ mutex_unlock(&sysfs_lock);
-+ return status ? : size;
-+}
-+
-+static const DEVICE_ATTR(drive, 0644,
-+ gpio_drive_show, gpio_drive_store);
-+
- static const struct attribute *gpio_attrs[] = {
- &dev_attr_value.attr,
- &dev_attr_active_low.attr,
-+ &dev_attr_drive.attr,
- NULL,
- };
-
-@@ -806,7 +892,7 @@ fail_unlock:
- }
- EXPORT_SYMBOL_GPL(gpio_export);
-
--static int match_export(struct device *dev, void *data)
-+static int match_export(struct device *dev, const void *data)
- {
- return dev_get_drvdata(dev) == data;
- }
-@@ -1677,6 +1763,50 @@ fail:
- }
- EXPORT_SYMBOL_GPL(gpio_set_debounce);
-
-+/**
-+ * gpio_set_drive - sets drive @mode for a @gpio
-+ * @gpio: the gpio to set the drive mode
-+ * @mode: the drive mode
-+ */
-+int gpio_set_drive(unsigned gpio, unsigned mode)
-+{
-+ unsigned long flags;
-+ struct gpio_chip *chip;
-+ struct gpio_desc *desc = &gpio_desc[gpio];
-+ int status = -EINVAL;
-+
-+ spin_lock_irqsave(&gpio_lock, flags);
-+
-+ if (!gpio_is_valid(gpio))
-+ goto fail;
-+ chip = desc->chip;
-+ if (!chip || !chip->set || !chip->set_drive)
-+ goto fail;
-+ gpio -= chip->base;
-+ if (gpio >= chip->ngpio)
-+ goto fail;
-+ status = gpio_ensure_requested(desc, gpio);
-+ if (status < 0)
-+ goto fail;
-+
-+ /* now we know the gpio is valid and chip won't vanish */
-+
-+ spin_unlock_irqrestore(&gpio_lock, flags);
-+
-+ might_sleep_if(chip->can_sleep);
-+
-+ return chip->set_drive(chip, gpio, mode);
-+
-+fail:
-+ spin_unlock_irqrestore(&gpio_lock, flags);
-+ if (status)
-+ pr_debug("%s: gpio-%d status %d\n",
-+ __func__, gpio, status);
-+
-+ return status;
-+}
-+EXPORT_SYMBOL_GPL(gpio_set_drive);
-+
- /* I/O calls are only valid after configuration completed; the relevant
- * "is this a valid GPIO" error checks should already have been done.
- *
-diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
-index bdca511..010e4fd 100644
---- a/drivers/i2c/busses/Kconfig
-+++ b/drivers/i2c/busses/Kconfig
-@@ -22,7 +22,7 @@ config I2C_ALI1535
-
- config I2C_ALI1563
- tristate "ALI 1563"
-- depends on PCI && EXPERIMENTAL
-+ depends on PCI
- help
- If you say yes to this option, support will be included for the SMB
- Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
-@@ -56,7 +56,7 @@ config I2C_AMD756
-
- config I2C_AMD756_S4882
- tristate "SMBus multiplexing on the Tyan S4882"
-- depends on I2C_AMD756 && X86 && EXPERIMENTAL
-+ depends on I2C_AMD756 && X86
- help
- Enabling this option will add specific SMBus support for the Tyan
- S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
-@@ -164,7 +164,7 @@ config I2C_NFORCE2
-
- config I2C_NFORCE2_S4985
- tristate "SMBus multiplexing on the Tyan S4985"
-- depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
-+ depends on I2C_NFORCE2 && X86
- help
- Enabling this option will add specific SMBus support for the Tyan
- S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
-@@ -215,7 +215,7 @@ config I2C_SIS96X
-
- config I2C_VIA
- tristate "VIA VT82C586B"
-- depends on PCI && EXPERIMENTAL
-+ depends on PCI
- select I2C_ALGOBIT
- help
- If you say yes to this option, support will be included for the VIA
-@@ -267,7 +267,7 @@ comment "Mac SMBus host controller drivers"
-
- config I2C_HYDRA
- tristate "CHRP Apple Hydra Mac I/O I2C interface"
-- depends on PCI && PPC_CHRP && EXPERIMENTAL
-+ depends on PCI && PPC_CHRP
- select I2C_ALGOBIT
- help
- This supports the use of the I2C interface in the Apple Hydra Mac
-@@ -293,7 +293,7 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
-
- config I2C_AT91
- tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
-- depends on ARCH_AT91 && EXPERIMENTAL
-+ depends on ARCH_AT91
- help
- This supports the use of the I2C interface on Atmel AT91
- processors.
-@@ -386,7 +386,7 @@ config I2C_DESIGNWARE_PLATFORM
-
- config I2C_DESIGNWARE_PCI
- tristate "Synopsys DesignWare PCI"
-- depends on PCI
-+ depends on PCI && !INTEL_QUARK_X1000_SOC
- select I2C_DESIGNWARE_CORE
- help
- If you say yes to this option, support will be included for the
-@@ -519,7 +519,6 @@ config I2C_NUC900
-
- config I2C_OCORES
- tristate "OpenCores I2C Controller"
-- depends on EXPERIMENTAL
- help
- If you say yes to this option, support will be included for the
- OpenCores I2C controller. For details see
-@@ -712,7 +711,7 @@ config I2C_OCTEON
-
- config I2C_XILINX
- tristate "Xilinx I2C Controller"
-- depends on EXPERIMENTAL && HAS_IOMEM
-+ depends on HAS_IOMEM
- help
- If you say yes to this option, support will be included for the
- Xilinx I2C controller.
-@@ -803,7 +802,7 @@ config I2C_PARPORT_LIGHT
-
- config I2C_TAOS_EVM
- tristate "TAOS evaluation module"
-- depends on EXPERIMENTAL
-+ depends on TTY
- select SERIO
- select SERIO_SERPORT
- default n
-diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
-index f5258c2..2a2d1c9 100644
---- a/drivers/i2c/busses/i2c-designware-core.c
-+++ b/drivers/i2c/busses/i2c-designware-core.c
-@@ -164,6 +164,29 @@ static char *abort_sources[] = {
- "lost arbitration",
- };
-
-+/*
-+ * Bitmask for struct i2c_dw_data_cmd's `cmd' field.
-+ * - DW_IC_CMD_READ: read/~write operation
-+ * - DW_IC_CMD_STOP: stop condition generation (only for devices requiring
-+ * explicit transaction termination)
-+ * - DW_IC_CMD_RESTART: (re)start condition generation (only for devices
-+ * requiring explicit transaction termination)
-+ */
-+#define DW_IC_CMD_READ 0x01
-+#define DW_IC_CMD_STOP 0x02
-+#define DW_IC_CMD_RESTART 0x04
-+
-+/*
-+ * Define the IC_DATA_CMD format.
-+ */
-+static union i2c_dw_data_cmd {
-+ struct fields {
-+ u8 data;
-+ u8 cmd;
-+ } fields;
-+ u16 value;
-+} data_cmd;
-+
- u32 dw_readl(struct dw_i2c_dev *dev, int offset)
- {
- u32 value;
-@@ -344,6 +367,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
- struct i2c_msg *msgs = dev->msgs;
- u32 ic_con;
-
-+ /* Disable interrupts */
-+ i2c_dw_disable_int(dev);
-+
- /* Disable the adapter */
- dw_writel(dev, 0, DW_IC_ENABLE);
-
-@@ -380,6 +406,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
- u32 addr = msgs[dev->msg_write_idx].addr;
- u32 buf_len = dev->tx_buf_len;
- u8 *buf = dev->tx_buf;
-+ int segment_start = 0;
-
- intr_mask = DW_IC_INTR_DEFAULT_MASK;
-
-@@ -403,21 +430,65 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
- break;
- }
-
-+ segment_start = 0;
- if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
- /* new i2c_msg */
- buf = msgs[dev->msg_write_idx].buf;
- buf_len = msgs[dev->msg_write_idx].len;
-+ segment_start = 1;
- }
-
- tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
- rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
-
-+ /*
-+ * The maximum number of read requests that can be put into TX
-+ * FIFO depends on the number read operations already pending
-+ * in RX FIFO + the number of outstanding read operations still
-+ * queued in the TX FIFO.
-+ * This prevents RX FIFO overrun.
-+ */
-+ rx_limit -= dev->rx_outstanding;
-+
- while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
-+ data_cmd.fields.data = 0x00;
-+ data_cmd.fields.cmd = 0x00;
-+
- if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
-- dw_writel(dev, 0x100, DW_IC_DATA_CMD);
-+ /* Master-receiver */
-+ data_cmd.fields.cmd = DW_IC_CMD_READ;
- rx_limit--;
-- } else
-- dw_writel(dev, *buf++, DW_IC_DATA_CMD);
-+ dev->rx_outstanding++;
-+ } else {
-+ /* Master-transmitter */
-+ data_cmd.fields.data = *buf;
-+ buf++;
-+ }
-+
-+ if (1 == dev->explicit_stop
-+ && 1 == segment_start) {
-+ /*
-+ * First byte of a transaction segment for a
-+ * device requiring explicit transaction
-+ * termination: generate (re)start symbol.
-+ */
-+ segment_start = 0;
-+ data_cmd.fields.cmd |= DW_IC_CMD_RESTART;
-+ }
-+
-+ if (1 == dev->explicit_stop
-+ && dev->msg_write_idx == dev->msgs_num - 1
-+ && 1 == buf_len) {
-+ /*
-+ * Last byte of last transction segment for a
-+ * device requiring explicit transaction
-+ * termination: generate stop symbol.
-+ */
-+ data_cmd.fields.cmd |= DW_IC_CMD_STOP;
-+ }
-+
-+ dw_writel(dev, data_cmd.value, DW_IC_DATA_CMD);
-+
- tx_limit--; buf_len--;
- }
-
-@@ -468,8 +539,10 @@ i2c_dw_read(struct dw_i2c_dev *dev)
-
- rx_valid = dw_readl(dev, DW_IC_RXFLR);
-
-- for (; len > 0 && rx_valid > 0; len--, rx_valid--)
-+ for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
- *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
-+ dev->rx_outstanding--;
-+ }
-
- if (len > 0) {
- dev->status |= STATUS_READ_IN_PROGRESS;
-@@ -527,6 +600,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
- dev->msg_err = 0;
- dev->status = STATUS_IDLE;
- dev->abort_source = 0;
-+ dev->rx_outstanding = 0;
-
- ret = i2c_dw_wait_bus_not_busy(dev);
- if (ret < 0)
-@@ -625,8 +699,6 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
- dw_readl(dev, DW_IC_CLR_RX_DONE);
- if (stat & DW_IC_INTR_ACTIVITY)
- dw_readl(dev, DW_IC_CLR_ACTIVITY);
-- if (stat & DW_IC_INTR_STOP_DET)
-- dw_readl(dev, DW_IC_CLR_STOP_DET);
- if (stat & DW_IC_INTR_START_DET)
- dw_readl(dev, DW_IC_CLR_START_DET);
- if (stat & DW_IC_INTR_GEN_CALL)
-@@ -677,8 +749,21 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
- * the current transmit status.
- */
-
-+ /*
-+ * Process stop condition after the last transaction segment is
-+ * transmitted (and received if appropriate).
-+ */
-+ if (dev->msgs_num == dev->msg_write_idx
-+ && (DW_IC_INTR_STOP_DET & dw_readl(dev, DW_IC_INTR_STAT))
-+ && 0 == dw_readl(dev, DW_IC_TXFLR)
-+ && 0 == dw_readl(dev, DW_IC_RXFLR)
-+ && 0 == dev->rx_outstanding) {
-+ dw_readl(dev, DW_IC_CLR_STOP_DET);
-+ complete(&dev->cmd_complete);
-+ }
-+
- tx_aborted:
-- if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
-+ if ((stat & (DW_IC_INTR_TX_ABRT)) || dev->msg_err)
- complete(&dev->cmd_complete);
-
- return IRQ_HANDLED;
-diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
-index 9c1840e..691aff8 100644
---- a/drivers/i2c/busses/i2c-designware-core.h
-+++ b/drivers/i2c/busses/i2c-designware-core.h
-@@ -34,6 +34,14 @@
- #define DW_IC_CON_RESTART_EN 0x20
- #define DW_IC_CON_SLAVE_DISABLE 0x40
-
-+struct dw_pci_controller {
-+ u32 bus_num;
-+ u32 bus_cfg;
-+ u32 tx_fifo_depth;
-+ u32 rx_fifo_depth;
-+ u32 clk_khz;
-+ u8 explicit_stop;
-+};
-
- /**
- * struct dw_i2c_dev - private i2c-designware data
-@@ -60,6 +68,8 @@
- * @adapter: i2c subsystem adapter node
- * @tx_fifo_depth: depth of the hardware tx fifo
- * @rx_fifo_depth: depth of the hardware rx fifo
-+ * @rx_outstanding: current outstanding master-receiver bytes in TX FIFO
-+ * @explicit_stop: set to 1 if hardware requires explicit stop bit transmission
- */
- struct dw_i2c_dev {
- struct device *dev;
-@@ -88,6 +98,8 @@ struct dw_i2c_dev {
- u32 master_cfg;
- unsigned int tx_fifo_depth;
- unsigned int rx_fifo_depth;
-+ int rx_outstanding;
-+ u8 explicit_stop;
- };
-
- #define ACCESS_SWAP 0x00000001
-diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
-index 6add851..62ad7dc 100644
---- a/drivers/i2c/busses/i2c-designware-pcidrv.c
-+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
-@@ -56,14 +56,6 @@ enum dw_pci_ctl_id_t {
- medfield_5,
- };
-
--struct dw_pci_controller {
-- u32 bus_num;
-- u32 bus_cfg;
-- u32 tx_fifo_depth;
-- u32 rx_fifo_depth;
-- u32 clk_khz;
--};
--
- #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
- DW_IC_CON_SLAVE_DISABLE | \
- DW_IC_CON_RESTART_EN)
-@@ -75,6 +67,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [moorestown_1] = {
- .bus_num = 1,
-@@ -82,6 +75,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [moorestown_2] = {
- .bus_num = 2,
-@@ -89,6 +83,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [medfield_0] = {
- .bus_num = 0,
-@@ -96,6 +91,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [medfield_1] = {
- .bus_num = 1,
-@@ -103,6 +99,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [medfield_2] = {
- .bus_num = 2,
-@@ -110,6 +107,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [medfield_3] = {
- .bus_num = 3,
-@@ -117,6 +115,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [medfield_4] = {
- .bus_num = 4,
-@@ -124,6 +123,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- [medfield_5] = {
- .bus_num = 5,
-@@ -131,6 +131,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
-+ .explicit_stop = 0,
- },
- };
- static struct i2c_algorithm i2c_dw_algo = {
-@@ -282,6 +283,7 @@ const struct pci_device_id *id)
-
- dev->tx_fifo_depth = controller->tx_fifo_depth;
- dev->rx_fifo_depth = controller->rx_fifo_depth;
-+ dev->explicit_stop = controller->explicit_stop;
- r = i2c_dw_init(dev);
- if (r)
- goto err_iounmap;
-diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
-index 05e996f..49a66c3 100644
---- a/drivers/iio/accel/Kconfig
-+++ b/drivers/iio/accel/Kconfig
-@@ -13,5 +13,13 @@ config HID_SENSOR_ACCEL_3D
- help
- Say yes here to build support for the HID SENSOR
- accelerometers 3D.
-+
-+config IIO_LIS331DLH_INTEL_CLN
-+ tristate "STMicroelectronics LIS331DLH accelerometer i2c driver for Intel Clanton platform"
-+ depends on INTEL_QUARK_X1000_SOC
-+ depends on I2C && SYSFS
-+ select IIO_ST_SENSORS_CORE
-+ help
-+ Selects the LIS331DLH accelerometer driver for the Intel Clanton Hill platform
-
- endmenu
-diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
-index 5bc6855..2ac0908 100644
---- a/drivers/iio/accel/Makefile
-+++ b/drivers/iio/accel/Makefile
-@@ -3,3 +3,5 @@
- #
-
- obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
-+
-+obj-$(CONFIG_IIO_LIS331DLH_INTEL_CLN) += lis331dlh_intel_cln.o
-diff --git a/drivers/iio/accel/lis331dlh_intel_cln.c b/drivers/iio/accel/lis331dlh_intel_cln.c
-new file mode 100644
-index 0000000..c76c30a
---- /dev/null
-+++ b/drivers/iio/accel/lis331dlh_intel_cln.c
-@@ -0,0 +1,735 @@
-+/*
-+ * Intel Clanton Hill platform accelerometer driver
-+ *
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ *
-+ * Derived from STMicroelectronics accelerometers driver by Denis Ciocca
-+ *
-+ * The Intel Clanton Hill platform hardware design includes an
-+ * STMicroelectronics LIS331DLH accelerometer, intended to be used mainly for
-+ * sensing orientation, movement and sudden impacts (e.g. vehicle collision)
-+ *
-+ * This driver plugs into the Linux Industrial-IO framework to provide a
-+ * standardised user-space application interface for retreiving data and events
-+ * from the accelerometer.
-+ *
-+ * The LIS331DLH is connected via I2C to the host CPU on the Clanton Hill
-+ * platform and so this driver registers to the kernel as an I2C device driver
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/types.h>
-+#include <linux/mutex.h>
-+#include <linux/interrupt.h>
-+#include <linux/i2c.h>
-+#include <linux/gpio.h>
-+#include <linux/iio/iio.h>
-+#include <linux/iio/sysfs.h>
-+#include <linux/iio/events.h>
-+
-+#include <linux/iio/common/st_sensors.h>
-+#include <linux/iio/common/st_sensors_i2c.h>
-+
-+#include <linux/platform_data/lis331dlh_intel_cln.h>
-+
-+/* DEFAULT VALUE FOR SENSORS */
-+#define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28
-+#define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a
-+#define ST_ACCEL_DEFAULT_OUT_Z_L_ADDR 0x2c
-+
-+/* FULLSCALE */
-+#define ST_ACCEL_FS_AVL_2G 2
-+#define ST_ACCEL_FS_AVL_4G 4
-+#define ST_ACCEL_FS_AVL_6G 6
-+#define ST_ACCEL_FS_AVL_8G 8
-+#define ST_ACCEL_FS_AVL_16G 16
-+
-+/* CUSTOM VALUES FOR SENSOR 2 */
-+#define ST_ACCEL_2_WAI_EXP 0x32
-+#define ST_ACCEL_2_ODR_ADDR 0x20
-+#define ST_ACCEL_2_ODR_MASK 0x18
-+#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00
-+#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01
-+#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02
-+#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03
-+#define ST_ACCEL_2_PW_ADDR 0x20
-+#define ST_ACCEL_2_PW_MASK 0xe0
-+#define ST_ACCEL_2_PW_DOWN 0x00
-+#define ST_ACCEL_2_PW_NORMAL 0x20
-+#define ST_ACCEL_2_CTRL_REG1_XEN 0x01
-+#define ST_ACCEL_2_CTRL_REG1_YEN 0x02
-+#define ST_ACCEL_2_CTRL_REG1_ZEN 0x04
-+#define ST_ACCEL_2_FS_ADDR 0x23
-+#define ST_ACCEL_2_FS_MASK 0x30
-+#define ST_ACCEL_2_FS_AVL_2_VAL 0X00
-+#define ST_ACCEL_2_FS_AVL_4_VAL 0X01
-+#define ST_ACCEL_2_FS_AVL_8_VAL 0x03
-+#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
-+#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
-+#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900)
-+#define ST_ACCEL_2_BDU_ADDR 0x23
-+#define ST_ACCEL_2_BDU_MASK 0x80
-+#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
-+#define ST_ACCEL_2_DRDY_IRQ_MASK 0x02
-+#define ST_ACCEL_2_THRESH_IRQ_ADDR 0x30
-+#define ST_ACCEL_2_THRESH_IRQ_MASK 0x7f
-+#define ST_ACCEL_2_INT1_CFG_ADDR 0x30
-+#define ST_ACCEL_2_INT1_SRC_ADDR 0x31
-+#define ST_ACCEL_2_INT1_THRESH_ADDR 0x32
-+#define ST_ACCEL_2_INT1_DURATION_ADDR 0x33
-+#define ST_ACCEL_2_INT2_CFG_ADDR 0x34
-+#define ST_ACCEL_2_INT2_SRC_ADDR 0x35
-+#define ST_ACCEL_2_INT2_THRESH_ADDR 0x36
-+#define ST_ACCEL_2_INT2_DURATION_ADDR 0x37
-+#define ST_ACCEL_2_INT_IA_MASK 0x40
-+#define ST_ACCEL_2_INT_LIR_MASK 0x05
-+#define ST_ACCEL_2_INT_SRC_HIGH_MASK 0x20
-+#define ST_ACCEL_2_INT_CFG_XLIE_EN 0x01
-+#define ST_ACCEL_2_INT_CFG_XHIE_EN 0x02
-+#define ST_ACCEL_2_INT_CFG_YLIE_EN 0x04
-+#define ST_ACCEL_2_INT_CFG_YHIE_EN 0x08
-+#define ST_ACCEL_2_INT_CFG_ZLIE_EN 0x10
-+#define ST_ACCEL_2_INT_CFG_ZHIE_EN 0x20
-+
-+#define ST_ACCEL_2_MULTIREAD_BIT true
-+#define ST_ACCEL_2_THRESH_VAL_MIN 0x00
-+#define ST_ACCEL_2_THRESH_VAL_MAX 0x7f
-+#define CLN_ACCEL_INT2_WAKEUP_THRESH_VAL 0x7f
-+
-+#define CLN_ACCEL_INT1_DISABLED 0
-+#define CLN_ACCEL_INT1_ENABLED 1
-+
-+#define CLN_ACCEL_LSM_CHANNELS(device_type, index, mod, endian, bits, addr) \
-+{ \
-+ .type = device_type, \
-+ .modified = 1, \
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
-+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
-+ .scan_index = index, \
-+ .channel = mod, \
-+ .channel2 = mod, \
-+ .address = addr, \
-+ .scan_type = { \
-+ .sign = 's', \
-+ .realbits = bits, \
-+ .shift = 16 - bits, \
-+ .storagebits = 16, \
-+ .endianness = endian, \
-+ }, \
-+ .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING), \
-+}
-+
-+static const u8 iio_modifier_map[] = {
-+ IIO_NO_MOD,
-+ IIO_MOD_X,
-+ IIO_MOD_Y,
-+ IIO_MOD_X_AND_Y,
-+ IIO_MOD_Z,
-+ IIO_MOD_X_AND_Z,
-+ IIO_MOD_Y_AND_Z,
-+ IIO_MOD_X_AND_Y_AND_Z,
-+};
-+
-+/* Threshold event ISR bottom half. This function reads interrupt status
-+ * registers for INT1 to reset any active interrupt conditions
-+ * and pushes an IIO event if a threshold interrupt was active.
-+ */
-+static irqreturn_t lis331dlh_intel_cln_threshold_event_handler(
-+ int irq,
-+ void *private)
-+{
-+ int err;
-+ u8 data;
-+ u8 mask;
-+ int i;
-+ u64 iio_modifier;
-+
-+ struct st_sensor_data *sdata = iio_priv(private);
-+ s64 timestamp = iio_get_time_ns();
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_SRC_ADDR,
-+ &data);
-+
-+ if (err < 0)
-+ goto st_sensors_read_err;
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_CFG_ADDR,
-+ &mask);
-+
-+ if (err < 0)
-+ goto st_sensors_read_err;
-+
-+ if (data & ST_ACCEL_2_INT_IA_MASK) {
-+ data &= mask;
-+
-+ iio_modifier = 0;
-+ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
-+ iio_modifier <<= 1;
-+ iio_modifier += !!(data & ST_ACCEL_2_INT_SRC_HIGH_MASK);
-+ data <<= 2;
-+ }
-+
-+ iio_modifier = iio_modifier_map[iio_modifier];
-+
-+ iio_push_event(private,
-+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
-+ 0,
-+ iio_modifier,
-+ IIO_EV_TYPE_THRESH,
-+ IIO_EV_DIR_RISING),
-+ timestamp);
-+ }
-+
-+st_sensors_read_err:
-+ return IRQ_HANDLED;
-+}
-+
-+static inline int lis331dlh_intel_cln_read_info_raw(struct iio_dev *indio_dev,
-+ struct iio_chan_spec const *ch, int *val)
-+{
-+ int err;
-+
-+ mutex_lock(&indio_dev->mlock);
-+ err = st_sensors_read_axis_data(indio_dev, ch->address, val);
-+
-+ if (unlikely(err < 0))
-+ goto read_error;
-+
-+ *val = *val >> ch->scan_type.shift;
-+ mutex_unlock(&indio_dev->mlock);
-+
-+ return err;
-+
-+read_error:
-+ mutex_unlock(&indio_dev->mlock);
-+ return err;
-+}
-+
-+static int lis331dlh_intel_cln_read_raw(
-+ struct iio_dev *indio_dev,
-+ struct iio_chan_spec const *ch,
-+ int *val, int *val2, long mask)
-+{
-+ int err;
-+ struct st_sensor_data *adata = iio_priv(indio_dev);
-+
-+ switch (mask) {
-+ case IIO_CHAN_INFO_RAW:
-+ err = lis331dlh_intel_cln_read_info_raw(indio_dev, ch, val);
-+ if (unlikely(err < 0))
-+ goto read_error;
-+
-+ return IIO_VAL_INT;
-+ case IIO_CHAN_INFO_SCALE:
-+ *val = 0;
-+ *val2 = adata->current_fullscale->gain;
-+ return IIO_VAL_INT_PLUS_MICRO;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+read_error:
-+ return err;
-+}
-+
-+static int lis331dlh_intel_cln_write_raw(
-+ struct iio_dev *indio_dev,
-+ struct iio_chan_spec const *chan,
-+ int val, int val2, long mask)
-+{
-+ int err;
-+
-+ switch (mask) {
-+ case IIO_CHAN_INFO_SCALE:
-+ err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return err;
-+}
-+
-+static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
-+static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
-+static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
-+
-+static struct attribute *lis331dlh_intel_cln_attributes[] = {
-+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
-+ &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
-+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
-+ NULL,
-+};
-+
-+static const struct attribute_group lis331dlh_intel_cln_attribute_group = {
-+ .attrs = lis331dlh_intel_cln_attributes,
-+};
-+
-+static int lis331dlh_intel_cln_read_event_value(
-+ struct iio_dev *indio_dev,
-+ u64 event_code,
-+ int *val)
-+{
-+ int err;
-+ u8 data;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_THRESH_ADDR, &data);
-+
-+ *val = (int) data;
-+ return err;
-+}
-+
-+static int lis331dlh_intel_cln_write_event_value(
-+ struct iio_dev *indio_dev,
-+ u64 event_code,
-+ int val)
-+{
-+ int err;
-+ struct st_sensor_data *sdata;
-+
-+ /* range check */
-+ if (unlikely((val < ST_ACCEL_2_THRESH_VAL_MIN) ||
-+ (val > ST_ACCEL_2_THRESH_VAL_MAX)))
-+ return -EINVAL;
-+
-+ sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_THRESH_ADDR, val);
-+
-+ return err;
-+}
-+
-+/* Configure the INT1 pin to fire an interrupt on a high threshold event.
-+ */
-+static int lis331dlh_intel_cln_configure_threshold_interrupt(
-+ struct iio_dev *indio_dev, u8 state)
-+{
-+ int err = 0;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ if (sdata->sensor->drdy_irq.ig1.en_mask == state)
-+ return 0;
-+
-+ if (state == CLN_ACCEL_INT1_ENABLED) {
-+ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
-+ NULL,
-+ lis331dlh_intel_cln_threshold_event_handler,
-+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-+ "lis331dlh_intel_cln_threshold",
-+ indio_dev);
-+ if (likely(err == 0)) {
-+ sdata->sensor->drdy_irq.ig1.en_mask =
-+ CLN_ACCEL_INT1_ENABLED;
-+ err = sdata->tf->write_byte(
-+ &sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_DURATION_ADDR, 1);
-+ }
-+ } else {
-+ free_irq(sdata->get_irq_data_ready(indio_dev), indio_dev);
-+ sdata->sensor->drdy_irq.ig1.en_mask = CLN_ACCEL_INT1_DISABLED;
-+ }
-+
-+ return err;
-+}
-+
-+static int lis331dlh_intel_cln_read_event_config(
-+ struct iio_dev *indio_dev,
-+ u64 event_code)
-+{
-+ int err = 0;
-+ u8 data, mask;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_CFG_ADDR,
-+ &data);
-+
-+ mask = 1 << ((IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code) << 1) - 1);
-+
-+ return !!(data & mask);
-+}
-+
-+static int lis331dlh_intel_cln_write_event_config(
-+ struct iio_dev *indio_dev,
-+ u64 event_code,
-+ int state)
-+{
-+ int err;
-+ u8 data;
-+ u8 mask;
-+
-+ bool new_int_state;
-+
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+ mask = 1 << ((IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code) << 1) - 1);
-+
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ ST_ACCEL_2_INT1_CFG_ADDR,
-+ mask, state);
-+ if (unlikely(err < 0))
-+ goto write_event_err;
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT1_CFG_ADDR, &data);
-+ if (unlikely(err < 0))
-+ goto write_event_err;
-+
-+ new_int_state = data & (ST_ACCEL_2_INT_CFG_XHIE_EN |
-+ ST_ACCEL_2_INT_CFG_YHIE_EN |
-+ ST_ACCEL_2_INT_CFG_ZHIE_EN);
-+ err = lis331dlh_intel_cln_configure_threshold_interrupt(
-+ indio_dev, new_int_state);
-+
-+write_event_err:
-+ return err;
-+}
-+
-+/* Configure the INT2 pin to fire an interrupt on a threshold high event. INT2
-+ * should be wired to a suspend well IRQ to wake up the host.
-+ */
-+static int lis331dlh_intel_cln_enable_wakeup_interrupt(
-+ struct iio_dev *indio_dev)
-+{
-+ int err = 0;
-+ u8 data;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_THRESH_ADDR,
-+ CLN_ACCEL_INT2_WAKEUP_THRESH_VAL);
-+ if (unlikely(err < 0))
-+ goto enable_wakeup_int_err;
-+
-+ /* Latch interrupt request on INT2 */
-+ err = st_sensors_write_data_with_mask(
-+ indio_dev, ST_ACCEL_2_DRDY_IRQ_ADDR,
-+ ST_ACCEL_2_INT_LIR_MASK, 1);
-+ if (unlikely(err < 0))
-+ goto enable_wakeup_int_err;
-+
-+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_DURATION_ADDR, 0);
-+ if (unlikely(err < 0))
-+ goto enable_wakeup_int_err;
-+
-+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_CFG_ADDR,
-+ ST_ACCEL_2_INT_CFG_XHIE_EN |
-+ ST_ACCEL_2_INT_CFG_YHIE_EN);
-+ if (unlikely(err < 0))
-+ goto enable_wakeup_int_err;
-+
-+ /* Clean ST_ACCEL_2_INT2_SRC */
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_SRC_ADDR,
-+ &data);
-+
-+enable_wakeup_int_err:
-+ return err;
-+}
-+
-+static int lis331dlh_intel_cln_disable_wakeup_interrupt(
-+ struct iio_dev *indio_dev)
-+{
-+ int err = 0;
-+ u8 data;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_CFG_ADDR,
-+ 0);
-+ if (unlikely(err < 0))
-+ goto disable_wakeup_int_err;
-+
-+ /* Clean ST_ACCEL_2_INT2_SRC */
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_SRC_ADDR,
-+ &data);
-+ if (unlikely(err < 0))
-+ goto disable_wakeup_int_err;
-+
-+disable_wakeup_int_err:
-+ return err;
-+}
-+
-+static int lis331dlh_intel_cln_handle_wakeup_interrupt(
-+ struct iio_dev *indio_dev)
-+{
-+ int err;
-+ u8 data;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+ s64 timestamp = iio_get_time_ns();
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_ACCEL_2_INT2_SRC_ADDR,
-+ &data);
-+ if (unlikely(err < 0))
-+ goto handle_wakeup_int_err;
-+
-+ if (data & ST_ACCEL_2_INT_IA_MASK) {
-+ iio_push_event(indio_dev,
-+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
-+ 0,
-+ IIO_MOD_X_OR_Y_OR_Z,
-+ IIO_EV_TYPE_THRESH,
-+ IIO_EV_DIR_EITHER),
-+ timestamp);
-+ }
-+
-+handle_wakeup_int_err:
-+ return err;
-+}
-+
-+static const struct iio_info accel_info = {
-+ .driver_module = THIS_MODULE,
-+ .attrs = &lis331dlh_intel_cln_attribute_group,
-+ .read_raw = &lis331dlh_intel_cln_read_raw,
-+ .write_raw = &lis331dlh_intel_cln_write_raw,
-+ .read_event_config = &lis331dlh_intel_cln_read_event_config,
-+ .write_event_config = &lis331dlh_intel_cln_write_event_config,
-+ .read_event_value = &lis331dlh_intel_cln_read_event_value,
-+ .write_event_value = &lis331dlh_intel_cln_write_event_value,
-+};
-+
-+static const struct iio_chan_spec st_accel_12bit_channels[] = {
-+ CLN_ACCEL_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
-+ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
-+ CLN_ACCEL_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
-+ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
-+ CLN_ACCEL_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
-+ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
-+ IIO_CHAN_SOFT_TIMESTAMP(3)
-+};
-+
-+static struct st_sensors lis331dlh_intel_cln_sensor = {
-+ .wai = ST_ACCEL_2_WAI_EXP,
-+ .sensors_supported = {
-+ [0] = "lis331dlh_cln",
-+ },
-+ .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
-+ .odr = {
-+ .addr = ST_ACCEL_2_ODR_ADDR,
-+ .mask = ST_ACCEL_2_ODR_MASK,
-+ .odr_avl = {
-+ { 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
-+ { 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
-+ { 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
-+ { 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
-+ },
-+ },
-+ .pw = {
-+ .addr = ST_ACCEL_2_PW_ADDR,
-+ .mask = ST_ACCEL_2_PW_MASK,
-+ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
-+ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
-+ },
-+ .enable_axis = {
-+ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
-+ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
-+ },
-+ .fs = {
-+ .addr = ST_ACCEL_2_FS_ADDR,
-+ .mask = ST_ACCEL_2_FS_MASK,
-+ .fs_avl = {
-+ [0] = {
-+ .num = ST_ACCEL_FS_AVL_2G,
-+ .value = ST_ACCEL_2_FS_AVL_2_VAL,
-+ .gain = ST_ACCEL_2_FS_AVL_2_GAIN,
-+ },
-+ [1] = {
-+ .num = ST_ACCEL_FS_AVL_4G,
-+ .value = ST_ACCEL_2_FS_AVL_4_VAL,
-+ .gain = ST_ACCEL_2_FS_AVL_4_GAIN,
-+ },
-+ [2] = {
-+ .num = ST_ACCEL_FS_AVL_8G,
-+ .value = ST_ACCEL_2_FS_AVL_8_VAL,
-+ .gain = ST_ACCEL_2_FS_AVL_8_GAIN,
-+ },
-+ },
-+ },
-+ .bdu = {
-+ .addr = ST_ACCEL_2_BDU_ADDR,
-+ .mask = ST_ACCEL_2_BDU_MASK,
-+ },
-+ .drdy_irq = {
-+ .addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
-+ .mask = ST_ACCEL_2_DRDY_IRQ_MASK,
-+ },
-+ .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
-+ .bootime = 2,
-+};
-+
-+static int lis331dlh_intel_cln_probe(
-+ struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct iio_dev *indio_dev;
-+ struct st_sensor_data *adata;
-+ struct lis331dlh_intel_cln_platform_data *pdata;
-+ int ret = 0;
-+
-+ indio_dev = iio_device_alloc(sizeof(*adata));
-+ if (unlikely(indio_dev == NULL)) {
-+ ret = -ENOMEM;
-+ goto iio_device_alloc_error;
-+ }
-+
-+ i2c_set_clientdata(client, indio_dev);
-+ indio_dev->dev.parent = &client->dev;
-+ indio_dev->name = client->name;
-+
-+ adata = iio_priv(indio_dev);
-+ adata->dev = &client->dev;
-+
-+ pdata = client->dev.platform_data;
-+ if (unlikely(!pdata)) {
-+ pr_err("No platform data provided\n");
-+ goto lis331dlh_intel_cln_init_err;
-+ }
-+
-+ ret = gpio_to_irq(pdata->irq1_pin);
-+ if (unlikely(ret < 0)) {
-+ pr_err(
-+ "Failed to obtain valid IRQ for GPIO %d, "
-+ "gpio_to_irq returned %d\n",
-+ pdata->irq1_pin, ret);
-+ goto lis331dlh_intel_cln_init_err;
-+ }
-+ to_i2c_client(adata->dev)->irq = ret;
-+
-+ st_sensors_i2c_configure(indio_dev, client, adata);
-+
-+ indio_dev->modes = INDIO_DIRECT_MODE;
-+ indio_dev->info = &accel_info;
-+
-+ ret = st_sensors_check_device_support(indio_dev,
-+ 1, &lis331dlh_intel_cln_sensor);
-+ if (unlikely(ret < 0))
-+ goto lis331dlh_intel_cln_init_err;
-+
-+ indio_dev->channels = adata->sensor->ch;
-+ indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
-+
-+ adata->multiread_bit = adata->sensor->multi_read_bit;
-+ adata->current_fullscale = (struct st_sensor_fullscale_avl *)
-+ &adata->sensor->fs.fs_avl[0];
-+ adata->odr = adata->sensor->odr.odr_avl[0].hz;
-+
-+ adata->sensor->drdy_irq.ig1.en_mask = CLN_ACCEL_INT1_DISABLED;
-+
-+ ret = st_sensors_init_sensor(indio_dev);
-+ if (unlikely(ret < 0))
-+ goto lis331dlh_intel_cln_init_err;
-+
-+ ret = st_sensors_set_enable(indio_dev, true);
-+ if (unlikely(ret < 0))
-+ goto lis331dlh_intel_cln_init_err;
-+
-+ ret = iio_device_register(indio_dev);
-+ if (unlikely(ret))
-+ goto lis331dlh_intel_cln_init_err;
-+
-+ return 0;
-+
-+lis331dlh_intel_cln_init_err:
-+ iio_device_free(indio_dev);
-+iio_device_alloc_error:
-+ return ret;
-+}
-+
-+static int lis331dlh_intel_cln_remove(
-+ struct i2c_client *client)
-+{
-+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
-+ struct st_sensor_data *adata = iio_priv(indio_dev);
-+
-+ st_sensors_set_enable(indio_dev, false);
-+
-+ if (adata->sensor->drdy_irq.ig1.en_mask == CLN_ACCEL_INT1_ENABLED)
-+ free_irq(adata->get_irq_data_ready(indio_dev), indio_dev);
-+
-+ iio_device_unregister(indio_dev);
-+
-+ iio_device_free(indio_dev);
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_PM
-+static int lis331dlh_intel_cln_suspend(
-+ struct device *dev)
-+{
-+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
-+
-+ lis331dlh_intel_cln_enable_wakeup_interrupt(indio_dev);
-+
-+ return 0;
-+}
-+
-+static int lis331dlh_intel_cln_resume(
-+ struct device *dev)
-+{
-+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
-+
-+ lis331dlh_intel_cln_handle_wakeup_interrupt(indio_dev);
-+ lis331dlh_intel_cln_disable_wakeup_interrupt(indio_dev);
-+
-+ return 0;
-+}
-+
-+static const struct dev_pm_ops lis331dlh_intel_cln_pm_ops = {
-+ .suspend = lis331dlh_intel_cln_suspend,
-+ .resume = lis331dlh_intel_cln_resume,
-+};
-+
-+#define LIS331DLH_INTEL_CLN_PM_OPS (&lis331dlh_intel_cln_pm_ops)
-+#else
-+#define LIS331DLH_INTEL_CLN_PM_OPS NULL
-+#endif
-+
-+static const struct i2c_device_id lis331dlh_intel_cln_id_table[] = {
-+ { "lis331dlh_cln" },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(i2c, lis331dlh_intel_cln_id_table);
-+
-+static struct i2c_driver lis331dlh_intel_cln_driver = {
-+ .driver = {
-+ .owner = THIS_MODULE,
-+ .name = "lis331dlh_cln",
-+ .pm = LIS331DLH_INTEL_CLN_PM_OPS,
-+ },
-+ .probe = lis331dlh_intel_cln_probe,
-+ .remove = lis331dlh_intel_cln_remove,
-+ .id_table = lis331dlh_intel_cln_id_table,
-+};
-+
-+module_i2c_driver(lis331dlh_intel_cln_driver);
-+
-+MODULE_AUTHOR("Wojciech Ziemba <wojciech.ziemba@emutex.com>");
-+MODULE_DESCRIPTION("STMicroelectronics LIS331DLH accelerometer i2c driver for Intel Clanton platform");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
-index b34d754..60491e4 100644
---- a/drivers/iio/adc/ad7298.c
-+++ b/drivers/iio/adc/ad7298.c
-@@ -33,7 +33,6 @@
- #define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
- #define AD7298_PDD (1 << 0) /* partial power down enable */
-
--#define AD7298_MAX_CHAN 8
- #define AD7298_BITS 12
- #define AD7298_STORAGE_BITS 16
- #define AD7298_INTREF_mV 2500
-@@ -46,6 +45,7 @@ struct ad7298_state {
- struct spi_device *spi;
- struct regulator *reg;
- unsigned ext_ref;
-+ u16 ext_vin_max[AD7298_MAX_CHAN];
- struct spi_transfer ring_xfer[10];
- struct spi_transfer scan_single_xfer[3];
- struct spi_message ring_msg;
-@@ -64,7 +64,7 @@ struct ad7298_state {
- .indexed = 1, \
- .channel = index, \
- .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
-- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
-+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- .address = index, \
- .scan_index = index, \
- .scan_type = { \
-@@ -269,7 +269,10 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
- case IIO_CHAN_INFO_SCALE:
- switch (chan->type) {
- case IIO_VOLTAGE:
-- *val = ad7298_get_ref_voltage(st);
-+ if (st->ext_vin_max[chan->channel])
-+ *val = st->ext_vin_max[chan->channel];
-+ else
-+ *val = ad7298_get_ref_voltage(st);
- *val2 = chan->scan_type.realbits;
- return IIO_VAL_FRACTIONAL_LOG2;
- case IIO_TEMP:
-@@ -304,8 +307,15 @@ static int ad7298_probe(struct spi_device *spi)
-
- st = iio_priv(indio_dev);
-
-- if (pdata && pdata->ext_ref)
-- st->ext_ref = AD7298_EXTREF;
-+ if (pdata) {
-+ int i;
-+
-+ if (pdata->ext_ref)
-+ st->ext_ref = AD7298_EXTREF;
-+
-+ for (i = 0; i < AD7298_MAX_CHAN; i++)
-+ st->ext_vin_max[i] = pdata->ext_vin_max[i];
-+ }
-
- if (st->ext_ref) {
- st->reg = regulator_get(&spi->dev, "vref");
-diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
-index ed45ee5..64bcb14 100644
---- a/drivers/iio/common/Kconfig
-+++ b/drivers/iio/common/Kconfig
-@@ -3,3 +3,4 @@
- #
-
- source "drivers/iio/common/hid-sensors/Kconfig"
-+source "drivers/iio/common/st_sensors/Kconfig"
-\ No newline at end of file
-diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
-index 8158400..c2352be 100644
---- a/drivers/iio/common/Makefile
-+++ b/drivers/iio/common/Makefile
-@@ -7,3 +7,4 @@
- #
-
- obj-y += hid-sensors/
-+obj-y += st_sensors/
-diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig
-new file mode 100644
-index 0000000..865f1ca
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/Kconfig
-@@ -0,0 +1,14 @@
-+#
-+# STMicroelectronics sensors common library
-+#
-+
-+config IIO_ST_SENSORS_I2C
-+ tristate
-+
-+config IIO_ST_SENSORS_SPI
-+ tristate
-+
-+config IIO_ST_SENSORS_CORE
-+ tristate
-+ select IIO_ST_SENSORS_I2C if I2C
-+ select IIO_ST_SENSORS_SPI if SPI_MASTER
-diff --git a/drivers/iio/common/st_sensors/Makefile b/drivers/iio/common/st_sensors/Makefile
-new file mode 100644
-index 0000000..9f3e24f
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/Makefile
-@@ -0,0 +1,10 @@
-+#
-+# Makefile for the STMicroelectronics sensor common modules.
-+#
-+
-+obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o
-+obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o
-+obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o
-+st_sensors-y := st_sensors_core.o
-+st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o
-+st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o
-diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
-new file mode 100644
-index 0000000..09b236d
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
-@@ -0,0 +1,116 @@
-+/*
-+ * STMicroelectronics sensors buffer library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/iio/iio.h>
-+#include <linux/iio/trigger.h>
-+#include <linux/interrupt.h>
-+#include <linux/iio/buffer.h>
-+#include <linux/iio/trigger_consumer.h>
-+#include <linux/iio/triggered_buffer.h>
-+#include <linux/irqreturn.h>
-+
-+#include <linux/iio/common/st_sensors.h>
-+
-+
-+int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
-+{
-+ int i, n = 0, len;
-+ u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS];
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
-+ if (test_bit(i, indio_dev->active_scan_mask)) {
-+ addr[n] = indio_dev->channels[i].address;
-+ n++;
-+ }
-+ }
-+ switch (n) {
-+ case 1:
-+ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-+ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf,
-+ sdata->multiread_bit);
-+ break;
-+ case 2:
-+ if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) {
-+ len = sdata->tf->read_multiple_byte(&sdata->tb,
-+ sdata->dev, addr[0],
-+ ST_SENSORS_BYTE_FOR_CHANNEL*n,
-+ buf, sdata->multiread_bit);
-+ } else {
-+ u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL*
-+ ST_SENSORS_NUMBER_DATA_CHANNELS];
-+ len = sdata->tf->read_multiple_byte(&sdata->tb,
-+ sdata->dev, addr[0],
-+ ST_SENSORS_BYTE_FOR_CHANNEL*
-+ ST_SENSORS_NUMBER_DATA_CHANNELS,
-+ rx_array, sdata->multiread_bit);
-+ if (len < 0)
-+ goto read_data_channels_error;
-+
-+ for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS;
-+ i++) {
-+ if (i < n)
-+ buf[i] = rx_array[i];
-+ else
-+ buf[i] = rx_array[n + i];
-+ }
-+ len = ST_SENSORS_BYTE_FOR_CHANNEL*n;
-+ }
-+ break;
-+ case 3:
-+ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-+ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL*
-+ ST_SENSORS_NUMBER_DATA_CHANNELS,
-+ buf, sdata->multiread_bit);
-+ break;
-+ default:
-+ len = -EINVAL;
-+ goto read_data_channels_error;
-+ }
-+ if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) {
-+ len = -EIO;
-+ goto read_data_channels_error;
-+ }
-+
-+read_data_channels_error:
-+ return len;
-+}
-+EXPORT_SYMBOL(st_sensors_get_buffer_element);
-+
-+irqreturn_t st_sensors_trigger_handler(int irq, void *p)
-+{
-+ int len;
-+ struct iio_poll_func *pf = p;
-+ struct iio_dev *indio_dev = pf->indio_dev;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
-+ if (len < 0)
-+ goto st_sensors_get_buffer_element_error;
-+
-+ if (indio_dev->scan_timestamp)
-+ *(s64 *)((u8 *)sdata->buffer_data +
-+ ALIGN(len, sizeof(s64))) = pf->timestamp;
-+
-+ iio_push_to_buffers(indio_dev, sdata->buffer_data);
-+
-+st_sensors_get_buffer_element_error:
-+ iio_trigger_notify_done(indio_dev->trig);
-+
-+ return IRQ_HANDLED;
-+}
-+EXPORT_SYMBOL(st_sensors_trigger_handler);
-+
-+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
-+MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
-new file mode 100644
-index 0000000..945a55b
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
-@@ -0,0 +1,447 @@
-+/*
-+ * STMicroelectronics sensors core library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/iio/iio.h>
-+#include <asm/unaligned.h>
-+
-+#include <linux/iio/common/st_sensors.h>
-+
-+
-+#define ST_SENSORS_WAI_ADDRESS 0x0f
-+
-+int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
-+ u8 reg_addr, u8 mask, u8 data)
-+{
-+ int err;
-+ u8 new_data;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
-+ if (err < 0)
-+ goto st_sensors_write_data_with_mask_error;
-+
-+ new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
-+ err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
-+
-+st_sensors_write_data_with_mask_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_write_data_with_mask);
-+
-+static int st_sensors_match_odr(struct st_sensors *sensor,
-+ unsigned int odr, struct st_sensor_odr_avl *odr_out)
-+{
-+ int i, ret = -EINVAL;
-+
-+ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
-+ if (sensor->odr.odr_avl[i].hz == 0)
-+ goto st_sensors_match_odr_error;
-+
-+ if (sensor->odr.odr_avl[i].hz == odr) {
-+ odr_out->hz = sensor->odr.odr_avl[i].hz;
-+ odr_out->value = sensor->odr.odr_avl[i].value;
-+ ret = 0;
-+ break;
-+ }
-+ }
-+
-+st_sensors_match_odr_error:
-+ return ret;
-+}
-+
-+int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
-+{
-+ int err;
-+ struct st_sensor_odr_avl odr_out = {0, 0};
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
-+ if (err < 0)
-+ goto st_sensors_match_odr_error;
-+
-+ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
-+ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
-+ if (sdata->enabled == true) {
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->odr.addr,
-+ sdata->sensor->odr.mask,
-+ odr_out.value);
-+ } else {
-+ err = 0;
-+ }
-+ } else {
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->odr.addr, sdata->sensor->odr.mask,
-+ odr_out.value);
-+ }
-+ if (err >= 0)
-+ sdata->odr = odr_out.hz;
-+
-+st_sensors_match_odr_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_set_odr);
-+
-+static int st_sensors_match_fs(struct st_sensors *sensor,
-+ unsigned int fs, int *index_fs_avl)
-+{
-+ int i, ret = -EINVAL;
-+
-+ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
-+ if (sensor->fs.fs_avl[i].num == 0)
-+ goto st_sensors_match_odr_error;
-+
-+ if (sensor->fs.fs_avl[i].num == fs) {
-+ *index_fs_avl = i;
-+ ret = 0;
-+ break;
-+ }
-+ }
-+
-+st_sensors_match_odr_error:
-+ return ret;
-+}
-+
-+static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
-+{
-+ int err, i = 0;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = st_sensors_match_fs(sdata->sensor, fs, &i);
-+ if (err < 0)
-+ goto st_accel_set_fullscale_error;
-+
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->fs.addr,
-+ sdata->sensor->fs.mask,
-+ sdata->sensor->fs.fs_avl[i].value);
-+ if (err < 0)
-+ goto st_accel_set_fullscale_error;
-+
-+ sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
-+ &sdata->sensor->fs.fs_avl[i];
-+ return err;
-+
-+st_accel_set_fullscale_error:
-+ dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
-+ return err;
-+}
-+
-+int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
-+{
-+ u8 tmp_value;
-+ int err = -EINVAL;
-+ bool found = false;
-+ struct st_sensor_odr_avl odr_out = {0, 0};
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ if (enable) {
-+ tmp_value = sdata->sensor->pw.value_on;
-+ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
-+ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
-+ err = st_sensors_match_odr(sdata->sensor,
-+ sdata->odr, &odr_out);
-+ if (err < 0)
-+ goto set_enable_error;
-+ tmp_value = odr_out.value;
-+ found = true;
-+ }
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->pw.addr,
-+ sdata->sensor->pw.mask, tmp_value);
-+ if (err < 0)
-+ goto set_enable_error;
-+
-+ sdata->enabled = true;
-+
-+ if (found)
-+ sdata->odr = odr_out.hz;
-+ } else {
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->pw.addr,
-+ sdata->sensor->pw.mask,
-+ sdata->sensor->pw.value_off);
-+ if (err < 0)
-+ goto set_enable_error;
-+
-+ sdata->enabled = false;
-+ }
-+
-+set_enable_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_set_enable);
-+
-+int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
-+{
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ return st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->enable_axis.addr,
-+ sdata->sensor->enable_axis.mask, axis_enable);
-+}
-+EXPORT_SYMBOL(st_sensors_set_axis_enable);
-+
-+int st_sensors_init_sensor(struct iio_dev *indio_dev)
-+{
-+ int err;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ mutex_init(&sdata->tb.buf_lock);
-+
-+ err = st_sensors_set_enable(indio_dev, false);
-+ if (err < 0)
-+ goto init_error;
-+
-+ err = st_sensors_set_fullscale(indio_dev,
-+ sdata->current_fullscale->num);
-+ if (err < 0)
-+ goto init_error;
-+
-+ err = st_sensors_set_odr(indio_dev, sdata->odr);
-+ if (err < 0)
-+ goto init_error;
-+
-+ /* set BDU */
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
-+ if (err < 0)
-+ goto init_error;
-+
-+ err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
-+
-+init_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_init_sensor);
-+
-+int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
-+{
-+ int err;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ /* Enable/Disable the interrupt generator 1. */
-+ if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->drdy_irq.ig1.en_addr,
-+ sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
-+ if (err < 0)
-+ goto st_accel_set_dataready_irq_error;
-+ }
-+
-+ /* Enable/Disable the interrupt generator for data ready. */
-+ err = st_sensors_write_data_with_mask(indio_dev,
-+ sdata->sensor->drdy_irq.addr,
-+ sdata->sensor->drdy_irq.mask, (int)enable);
-+
-+st_accel_set_dataready_irq_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_set_dataready_irq);
-+
-+int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
-+{
-+ int err = -EINVAL, i;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
-+ if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
-+ (sdata->sensor->fs.fs_avl[i].gain != 0)) {
-+ err = 0;
-+ break;
-+ }
-+ }
-+ if (err < 0)
-+ goto st_sensors_match_scale_error;
-+
-+ err = st_sensors_set_fullscale(indio_dev,
-+ sdata->sensor->fs.fs_avl[i].num);
-+
-+st_sensors_match_scale_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
-+
-+int st_sensors_read_axis_data(struct iio_dev *indio_dev,
-+ u8 ch_addr, int *data)
-+{
-+ int err;
-+ u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL];
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
-+ ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL,
-+ outdata, sdata->multiread_bit);
-+ if (err < 0)
-+ goto read_error;
-+
-+ *data = (s16)get_unaligned_le16(outdata);
-+
-+read_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_read_axis_data);
-+
-+int st_sensors_read_info_raw(struct iio_dev *indio_dev,
-+ struct iio_chan_spec const *ch, int *val)
-+{
-+ int err;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ mutex_lock(&indio_dev->mlock);
-+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
-+ err = -EBUSY;
-+ goto read_error;
-+ } else {
-+ err = st_sensors_set_enable(indio_dev, true);
-+ if (err < 0)
-+ goto read_error;
-+
-+ msleep((sdata->sensor->bootime * 1000) / sdata->odr);
-+ err = st_sensors_read_axis_data(indio_dev, ch->address, val);
-+ if (err < 0)
-+ goto read_error;
-+
-+ *val = *val >> ch->scan_type.shift;
-+ }
-+ mutex_unlock(&indio_dev->mlock);
-+
-+ return err;
-+
-+read_error:
-+ mutex_unlock(&indio_dev->mlock);
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_read_info_raw);
-+
-+int st_sensors_check_device_support(struct iio_dev *indio_dev,
-+ int num_sensors_list, const struct st_sensors *sensors)
-+{
-+ u8 wai;
-+ int i, n, err;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
-+ ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
-+ if (err < 0) {
-+ dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
-+ goto read_wai_error;
-+ }
-+
-+ for (i = 0; i < num_sensors_list; i++) {
-+ if (sensors[i].wai == wai)
-+ break;
-+ }
-+ if (i == num_sensors_list)
-+ goto device_not_supported;
-+
-+ for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
-+ if (strcmp(indio_dev->name,
-+ &sensors[i].sensors_supported[n][0]) == 0)
-+ break;
-+ }
-+ if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
-+ dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
-+ goto sensor_name_mismatch;
-+ }
-+
-+ sdata->sensor = (struct st_sensors *)&sensors[i];
-+
-+ return i;
-+
-+device_not_supported:
-+ dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
-+sensor_name_mismatch:
-+ err = -ENODEV;
-+read_wai_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_check_device_support);
-+
-+ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
-+
-+ return sprintf(buf, "%d\n", adata->odr);
-+}
-+EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
-+
-+ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t size)
-+{
-+ int err;
-+ unsigned int odr;
-+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
-+
-+ err = kstrtoint(buf, 10, &odr);
-+ if (err < 0)
-+ goto conversion_error;
-+
-+ mutex_lock(&indio_dev->mlock);
-+ err = st_sensors_set_odr(indio_dev, odr);
-+ mutex_unlock(&indio_dev->mlock);
-+
-+conversion_error:
-+ return err < 0 ? err : size;
-+}
-+EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
-+
-+ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ int i, len = 0;
-+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ mutex_lock(&indio_dev->mlock);
-+ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
-+ if (sdata->sensor->odr.odr_avl[i].hz == 0)
-+ break;
-+
-+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
-+ sdata->sensor->odr.odr_avl[i].hz);
-+ }
-+ mutex_unlock(&indio_dev->mlock);
-+ buf[len - 1] = '\n';
-+
-+ return len;
-+}
-+EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
-+
-+ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ int i, len = 0;
-+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ mutex_lock(&indio_dev->mlock);
-+ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
-+ if (sdata->sensor->fs.fs_avl[i].num == 0)
-+ break;
-+
-+ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
-+ sdata->sensor->fs.fs_avl[i].gain);
-+ }
-+ mutex_unlock(&indio_dev->mlock);
-+ buf[len - 1] = '\n';
-+
-+ return len;
-+}
-+EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
-+
-+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
-+MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
-new file mode 100644
-index 0000000..38af944
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
-@@ -0,0 +1,81 @@
-+/*
-+ * STMicroelectronics sensors i2c library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/iio/iio.h>
-+
-+#include <linux/iio/common/st_sensors_i2c.h>
-+
-+
-+#define ST_SENSORS_I2C_MULTIREAD 0x80
-+
-+static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
-+{
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ return to_i2c_client(sdata->dev)->irq;
-+}
-+
-+static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, u8 *res_byte)
-+{
-+ int err;
-+
-+ err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
-+ if (err < 0)
-+ goto st_accel_i2c_read_byte_error;
-+
-+ *res_byte = err & 0xff;
-+
-+st_accel_i2c_read_byte_error:
-+ return err < 0 ? err : 0;
-+}
-+
-+static int st_sensors_i2c_read_multiple_byte(
-+ struct st_sensor_transfer_buffer *tb, struct device *dev,
-+ u8 reg_addr, int len, u8 *data, bool multiread_bit)
-+{
-+ if (multiread_bit)
-+ reg_addr |= ST_SENSORS_I2C_MULTIREAD;
-+
-+ return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
-+ reg_addr, len, data);
-+}
-+
-+static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, u8 data)
-+{
-+ return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
-+}
-+
-+static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
-+ .read_byte = st_sensors_i2c_read_byte,
-+ .write_byte = st_sensors_i2c_write_byte,
-+ .read_multiple_byte = st_sensors_i2c_read_multiple_byte,
-+};
-+
-+void st_sensors_i2c_configure(struct iio_dev *indio_dev,
-+ struct i2c_client *client, struct st_sensor_data *sdata)
-+{
-+ i2c_set_clientdata(client, indio_dev);
-+
-+ indio_dev->dev.parent = &client->dev;
-+ indio_dev->name = client->name;
-+
-+ sdata->tf = &st_sensors_tf_i2c;
-+ sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
-+}
-+EXPORT_SYMBOL(st_sensors_i2c_configure);
-+
-+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
-+MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
-new file mode 100644
-index 0000000..f0aa2f1
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
-@@ -0,0 +1,128 @@
-+/*
-+ * STMicroelectronics sensors spi library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/iio/iio.h>
-+
-+#include <linux/iio/common/st_sensors_spi.h>
-+
-+
-+#define ST_SENSORS_SPI_MULTIREAD 0xc0
-+#define ST_SENSORS_SPI_READ 0x80
-+
-+static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
-+{
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ return to_spi_device(sdata->dev)->irq;
-+}
-+
-+static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
-+{
-+ struct spi_message msg;
-+ int err;
-+
-+ struct spi_transfer xfers[] = {
-+ {
-+ .tx_buf = tb->tx_buf,
-+ .bits_per_word = 8,
-+ .len = 1,
-+ },
-+ {
-+ .rx_buf = tb->rx_buf,
-+ .bits_per_word = 8,
-+ .len = len,
-+ }
-+ };
-+
-+ mutex_lock(&tb->buf_lock);
-+ if ((multiread_bit) && (len > 1))
-+ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
-+ else
-+ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
-+
-+ spi_message_init(&msg);
-+ spi_message_add_tail(&xfers[0], &msg);
-+ spi_message_add_tail(&xfers[1], &msg);
-+ err = spi_sync(to_spi_device(dev), &msg);
-+ if (err)
-+ goto acc_spi_read_error;
-+
-+ memcpy(data, tb->rx_buf, len*sizeof(u8));
-+ mutex_unlock(&tb->buf_lock);
-+ return len;
-+
-+acc_spi_read_error:
-+ mutex_unlock(&tb->buf_lock);
-+ return err;
-+}
-+
-+static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, u8 *res_byte)
-+{
-+ return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
-+}
-+
-+static int st_sensors_spi_read_multiple_byte(
-+ struct st_sensor_transfer_buffer *tb, struct device *dev,
-+ u8 reg_addr, int len, u8 *data, bool multiread_bit)
-+{
-+ return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
-+}
-+
-+static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, u8 data)
-+{
-+ struct spi_message msg;
-+ int err;
-+
-+ struct spi_transfer xfers = {
-+ .tx_buf = tb->tx_buf,
-+ .bits_per_word = 8,
-+ .len = 2,
-+ };
-+
-+ mutex_lock(&tb->buf_lock);
-+ tb->tx_buf[0] = reg_addr;
-+ tb->tx_buf[1] = data;
-+
-+ spi_message_init(&msg);
-+ spi_message_add_tail(&xfers, &msg);
-+ err = spi_sync(to_spi_device(dev), &msg);
-+ mutex_unlock(&tb->buf_lock);
-+
-+ return err;
-+}
-+
-+static const struct st_sensor_transfer_function st_sensors_tf_spi = {
-+ .read_byte = st_sensors_spi_read_byte,
-+ .write_byte = st_sensors_spi_write_byte,
-+ .read_multiple_byte = st_sensors_spi_read_multiple_byte,
-+};
-+
-+void st_sensors_spi_configure(struct iio_dev *indio_dev,
-+ struct spi_device *spi, struct st_sensor_data *sdata)
-+{
-+ spi_set_drvdata(spi, indio_dev);
-+
-+ indio_dev->dev.parent = &spi->dev;
-+ indio_dev->name = spi->modalias;
-+
-+ sdata->tf = &st_sensors_tf_spi;
-+ sdata->get_irq_data_ready = st_sensors_spi_get_irq;
-+}
-+EXPORT_SYMBOL(st_sensors_spi_configure);
-+
-+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
-+MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
-new file mode 100644
-index 0000000..139ed03
---- /dev/null
-+++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
-@@ -0,0 +1,77 @@
-+/*
-+ * STMicroelectronics sensors trigger library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/slab.h>
-+#include <linux/iio/iio.h>
-+#include <linux/iio/trigger.h>
-+#include <linux/interrupt.h>
-+
-+#include <linux/iio/common/st_sensors.h>
-+
-+
-+int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
-+ const struct iio_trigger_ops *trigger_ops)
-+{
-+ int err;
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
-+ if (sdata->trig == NULL) {
-+ err = -ENOMEM;
-+ dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
-+ goto iio_trigger_alloc_error;
-+ }
-+
-+ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
-+ iio_trigger_generic_data_rdy_poll,
-+ NULL,
-+ IRQF_TRIGGER_RISING,
-+ sdata->trig->name,
-+ sdata->trig);
-+ if (err)
-+ goto request_irq_error;
-+
-+ sdata->trig->private_data = indio_dev;
-+ sdata->trig->ops = trigger_ops;
-+ sdata->trig->dev.parent = sdata->dev;
-+
-+ err = iio_trigger_register(sdata->trig);
-+ if (err < 0) {
-+ dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
-+ goto iio_trigger_register_error;
-+ }
-+ indio_dev->trig = sdata->trig;
-+
-+ return 0;
-+
-+iio_trigger_register_error:
-+ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
-+request_irq_error:
-+ iio_trigger_free(sdata->trig);
-+iio_trigger_alloc_error:
-+ return err;
-+}
-+EXPORT_SYMBOL(st_sensors_allocate_trigger);
-+
-+void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
-+{
-+ struct st_sensor_data *sdata = iio_priv(indio_dev);
-+
-+ iio_trigger_unregister(sdata->trig);
-+ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
-+ iio_trigger_free(sdata->trig);
-+}
-+EXPORT_SYMBOL(st_sensors_deallocate_trigger);
-+
-+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
-+MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
-index aaadd32..7b8d510 100644
---- a/drivers/iio/industrialio-buffer.c
-+++ b/drivers/iio/industrialio-buffer.c
-@@ -119,8 +119,8 @@ static ssize_t iio_scan_el_show(struct device *dev,
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-
-- ret = test_bit(to_iio_dev_attr(attr)->address,
-- indio_dev->buffer->scan_mask);
-+ ret = abs(test_bit(to_iio_dev_attr(attr)->address,
-+ indio_dev->buffer->scan_mask));
-
- return sprintf(buf, "%d\n", ret);
- }
-@@ -762,7 +762,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev,
- if (!buffer->scan_mask)
- return 0;
-
-- return test_bit(bit, buffer->scan_mask);
-+ return abs(test_bit(bit, buffer->scan_mask));
- };
- EXPORT_SYMBOL_GPL(iio_scan_mask_query);
-
-diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
-index 3e24571..da30c5c 100644
---- a/drivers/isdn/mISDN/core.c
-+++ b/drivers/isdn/mISDN/core.c
-@@ -168,13 +168,13 @@ static struct class mISDN_class = {
- };
-
- static int
--_get_mdevice(struct device *dev, void *id)
-+_get_mdevice(struct device *dev, const void *id)
- {
- struct mISDNdevice *mdev = dev_to_mISDN(dev);
-
- if (!mdev)
- return 0;
-- if (mdev->id != *(u_int *)id)
-+ if (mdev->id != *(const u_int *)id)
- return 0;
- return 1;
- }
-diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
-index ff553ba..edd3b4c 100644
---- a/drivers/mfd/Kconfig
-+++ b/drivers/mfd/Kconfig
-@@ -907,6 +907,44 @@ config MFD_TIMBERDALE
- The timberdale FPGA can be found on the Intel Atom development board
- for in-vehicle infontainment, called Russellville.
-
-+config CY8C9540A
-+ tristate "Cypress CY8C9540 GPIO/PWM expander"
-+ depends on GPIOLIB
-+ depends on I2C
-+ depends on PWM
-+ help
-+ 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 INTEL_CLN_GIP
-+ tristate "Intel Clanton GIP"
-+ depends on PCI && X86 && INTEL_QUARK_X1000_SOC
-+ depends on I2C
-+ select GENERIC_IRQ_CHIP
-+ help
-+ GIP driver for Clanton SoC.
-+ Clanton GIP is a single PCI function exporting a GPIO and an I2C
-+ controller, namely Synopsys DesignWare GPIO and Synopsys DesignWare
-+ I2C. The GPIO interface exports a total amount of 8 interrupt-capable
-+ GPIOs.
-+
-+config INTEL_CLN_GIP_TEST
-+ tristate "Intel Clanton GIP support for Integration Testing"
-+ depends on INTEL_CLN_GIP
-+ select I2C_CHARDEV
-+ select GPIO_SYSFS
-+ select SPI
-+ select SPI_BITBANG
-+ select SPI_GPIO
-+ select SPI_MASTER
-+ select SPI_SPIDEV
-+ help
-+ Clanton GIP automated Integration Testing package.
-+ It selects kernel components needed for GPIO and I2C tests as per
-+ Integration Test Specification, and it also adds a kernel-space
-+ facility for testing the GPIO.
-+ Note this module is also used to test the Clanton Legacy GPIO.
-+
- config LPC_SCH
- tristate "Intel SCH LPC"
- depends on PCI
-diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
-index 8b977f8..fda016c 100644
---- a/drivers/mfd/Makefile
-+++ b/drivers/mfd/Makefile
-@@ -123,6 +123,14 @@ 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
-+obj-$(CONFIG_INTEL_CLN_GIP) += intel_cln_gip.o
-+intel_cln_gip-objs := intel_cln_gip_core.o \
-+ intel_cln_gip_gpio.o \
-+ intel_cln_gip_i2c.o \
-+ ../i2c/busses/i2c-designware-core.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_gip_pdata.o
-+obj-$(CONFIG_INTEL_CLN_GIP_TEST)+=intel_cln_gip_test.o
- obj-$(CONFIG_LPC_SCH) += lpc_sch.o
- obj-$(CONFIG_LPC_ICH) += lpc_ich.o
- 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..0e4ea5e
---- /dev/null
-+++ b/drivers/mfd/cy8c9540a.c
-@@ -0,0 +1,970 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+
-+/*
-+ * Driver for Cypress CY8C9540A I/O Expander and PWM
-+ *
-+ * The I/O Expander is I2C-controlled and provides 40 interrupt-capable GPIOs,
-+ * 8 PWMs and an EEPROM.
-+ * Note the device only supports I2C standard speed 100kHz.
-+ *
-+ * Based on gpio-adp5588.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/i2c.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/gpio.h>
-+#include <linux/kernel.h>
-+#include <linux/mfd/cy8c9540a.h>
-+#include <linux/module.h>
-+#include <linux/pwm.h>
-+#include <linux/slab.h>
-+
-+#define DRV_NAME "cy8c9540a"
-+
-+/* CY8C9540A settings */
-+#define NGPIO 40
-+#define PWM_MAX_PERIOD 0xff
-+#define DEVID_FAMILY_CY8C9540A 0x40
-+#define DEVID_FAMILY_MASK 0xf0
-+#define NPORTS 6
-+#define PWM_CLK 0x00 /* see resulting PWM_TCLK_NS */
-+#define PWM_TCLK_NS 31250 /* 32kHz */
-+
-+/* Register offset */
-+#define REG_INPUT_PORT0 0x00
-+#define REG_OUTPUT_PORT0 0x08
-+#define REG_INTR_STAT_PORT0 0x10
-+#define REG_PORT_SELECT 0x18
-+#define REG_INTR_MASK 0x19
-+#define REG_SELECT_PWM 0x1a
-+#define REG_PIN_DIR 0x1c
-+#define REG_DRIVE_PULLUP 0x1d
-+#define REG_PWM_SELECT 0x28
-+#define REG_PWM_CLK 0x29
-+#define REG_PWM_PERIOD 0x2a
-+#define REG_PWM_PULSE_W 0x2b
-+#define REG_ENABLE 0x2d
-+#define REG_DEVID_STAT 0x2e
-+#define REG_CMD 0x30
-+
-+/* Commands */
-+#define CMD_W_EEPROM_POR 0x03
-+#define CMD_R_EEPROM_POR 0x04
-+#define CMD_RECONF 0x07
-+
-+/* Max retries after I2C NAK */
-+#define MAX_RETRIES 3
-+
-+/*
-+ * Wait time for device to be ready.
-+ * Note the time the part takes depends on the user configuration (mainly on
-+ * the number of active interrupts). The minimum delay here covers the
-+ * worst-case scenario.
-+ */
-+#define SLEEP_US_MIN 4000
-+#define SLEEP_US_MAX 4500
-+
-+/* Command string to store platform POR settings */
-+#define POR_CMD_W_OFFS 2
-+static u8 por_set[CY8C9540A_POR_SETTINGS_LEN + POR_CMD_W_OFFS] = {
-+ [0] = REG_CMD,
-+ [1] = CMD_W_EEPROM_POR,
-+};
-+
-+struct cy8c9540a {
-+ struct i2c_client *client;
-+ struct gpio_chip gpio_chip;
-+ struct pwm_chip pwm_chip;
-+ struct mutex lock;
-+ /* IRQ base stored from platform data */
-+ int irq_base;
-+ /* protect serialized access to the interrupt controller bus */
-+ struct mutex irq_lock;
-+ /* cached output registers */
-+ u8 outreg_cache[NPORTS];
-+ /* cached IRQ mask */
-+ u8 irq_mask_cache[NPORTS];
-+ /* IRQ mask to be applied */
-+ u8 irq_mask[NPORTS];
-+ /* Descriptor for raw i2c transactions */
-+ struct i2c_msg i2c_segments[2];
-+ /* POR settings stored in the EEPROM */
-+ u8 por_stored[CY8C9540A_POR_SETTINGS_LEN];
-+ /* PWM-to-GPIO mapping (0 == first gpio pin) */
-+ int pwm2gpio_mapping[CY8C9540A_NPWM];
-+};
-+
-+/* Per-port GPIO offset */
-+static const u8 cy8c9540a_port_offs[] = {
-+ 0,
-+ 8,
-+ 16,
-+ 20,
-+ 28,
-+ 36,
-+};
-+
-+static inline u8 cypress_get_port(unsigned gpio)
-+{
-+ u8 i = 0;
-+ for (i = 0; i < sizeof(cy8c9540a_port_offs) - 1; i ++) {
-+ if (! (gpio / cy8c9540a_port_offs[i + 1]))
-+ break;
-+ }
-+ return i;
-+}
-+
-+static inline u8 cypress_get_offs(unsigned gpio, u8 port)
-+{
-+ return gpio - cy8c9540a_port_offs[port];
-+}
-+
-+static int cy8c9540a_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-+{
-+ s32 ret = 0;
-+ u8 port = 0;
-+ u8 in_reg = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, gpio_chip);
-+ struct i2c_client *client = dev->client;
-+
-+ port = cypress_get_port(gpio);
-+ in_reg = REG_INPUT_PORT0 + port;
-+
-+ ret = i2c_smbus_read_byte_data(client, in_reg);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't read input port%u\n", in_reg);
-+ }
-+
-+ return !!(ret & BIT(cypress_get_offs(gpio, port)));
-+}
-+
-+static void cy8c9540a_gpio_set_value(struct gpio_chip *chip,
-+ unsigned gpio, int val)
-+{
-+ s32 ret = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, gpio_chip);
-+ struct i2c_client *client = dev->client;
-+ u8 port = cypress_get_port(gpio);
-+ u8 out_reg = REG_OUTPUT_PORT0 + port;
-+
-+ mutex_lock(&dev->lock);
-+
-+ if (val) {
-+ dev->outreg_cache[port] |= BIT(cypress_get_offs(gpio, port));
-+ } else {
-+ dev->outreg_cache[port] &= ~BIT(cypress_get_offs(gpio, port));
-+ }
-+
-+ ret = i2c_smbus_write_byte_data(client, out_reg,
-+ dev->outreg_cache[port]);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write output port%u\n", port);
-+ }
-+
-+ mutex_unlock(&dev->lock);
-+}
-+
-+static int cy8c9540a_gpio_set_drive(struct gpio_chip *chip, unsigned gpio,
-+ unsigned mode)
-+{
-+ s32 ret = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, gpio_chip);
-+ struct i2c_client *client = dev->client;
-+ u8 port = cypress_get_port(gpio);
-+ u8 pin = cypress_get_offs(gpio, port);
-+ u8 offs = 0;
-+ u8 val = 0;
-+
-+ switch(mode) {
-+ case GPIOF_DRIVE_PULLUP:
-+ offs = 0x0;
-+ break;
-+ case GPIOF_DRIVE_STRONG:
-+ offs = 0x4;
-+ break;
-+ case GPIOF_DRIVE_HIZ:
-+ offs = 0x6;
-+ break;
-+ default:
-+ /*
-+ * See databook for alternative modes. This driver won't
-+ * support them though.
-+ */
-+ return -EINVAL;
-+ break;
-+ }
-+
-+ mutex_lock(&dev->lock);
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't select port %u\n", port);
-+ goto end;
-+ }
-+
-+ ret = i2c_smbus_read_byte_data(client, REG_DRIVE_PULLUP + offs);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't read pin direction\n");
-+ goto end;
-+ }
-+
-+ val = (u8)(ret | BIT(pin));
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_DRIVE_PULLUP + offs, val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't set drive mode port %u\n", port);
-+ goto end;
-+ }
-+
-+ ret = 0;
-+
-+end:
-+ mutex_unlock(&dev->lock);
-+ return ret;
-+}
-+
-+static int cy8c9540a_gpio_direction(struct gpio_chip *chip, unsigned gpio,
-+ int out, int val)
-+{
-+ s32 ret = 0;
-+ u8 pins = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, gpio_chip);
-+ struct i2c_client *client = dev->client;
-+ u8 port = cypress_get_port(gpio);
-+
-+ ret = cy8c9540a_gpio_set_drive(chip, gpio, out ?
-+ GPIOF_DRIVE_STRONG : GPIOF_DRIVE_HIZ);
-+ if (ret) {
-+ return ret;
-+ }
-+
-+ mutex_lock(&dev->lock);
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't select port %u\n", port);
-+ goto end;
-+ }
-+
-+ ret = i2c_smbus_read_byte_data(client, REG_PIN_DIR);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't read pin direction\n");
-+ goto end;
-+ }
-+
-+ pins = (u8)ret & 0xff;
-+ if (out) {
-+ pins &= ~BIT(cypress_get_offs(gpio, port));
-+ } else {
-+ pins |= BIT(cypress_get_offs(gpio, port));
-+ }
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_PIN_DIR, pins);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write pin direction\n");
-+ }
-+
-+end:
-+ mutex_unlock(&dev->lock);
-+ return ret;
-+}
-+
-+static int cy8c9540a_gpio_direction_output(struct gpio_chip *chip,
-+ unsigned gpio, int val)
-+{
-+ return cy8c9540a_gpio_direction(chip, gpio, 1, val);
-+}
-+
-+static int cy8c9540a_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-+{
-+ return cy8c9540a_gpio_direction(chip, gpio, 0, 0);
-+}
-+
-+static void cy8c9540a_irq_bus_lock(struct irq_data *d)
-+{
-+ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
-+ mutex_lock(&dev->irq_lock);
-+}
-+
-+static void cy8c9540a_irq_bus_sync_unlock(struct irq_data *d)
-+{
-+ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
-+ struct i2c_client *client = dev->client;
-+ int ret = 0;
-+ int i = 0;
-+
-+ for (i = 0; i < NPORTS; i++) {
-+ if (dev->irq_mask_cache[i] ^ dev->irq_mask[i]) {
-+ dev->irq_mask_cache[i] = dev->irq_mask[i];
-+ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, i);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't select port %u\n", i);
-+ goto end;
-+ }
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_INTR_MASK, dev->irq_mask[i]);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write int mask on port %u\n", i);
-+ goto end;
-+ }
-+
-+ }
-+ }
-+
-+end:
-+ mutex_unlock(&dev->irq_lock);
-+}
-+
-+static void cy8c9540a_irq_mask(struct irq_data *d)
-+{
-+ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
-+ unsigned gpio = d->irq - dev->irq_base;
-+ u8 port = cypress_get_port(gpio);
-+
-+ dev->irq_mask[port] |= BIT(cypress_get_offs(gpio, port));
-+}
-+
-+static void cy8c9540a_irq_unmask(struct irq_data *d)
-+{
-+ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
-+ unsigned gpio = d->irq - dev->irq_base;
-+ u8 port = cypress_get_port(gpio);
-+
-+ dev->irq_mask[port] &= ~BIT(cypress_get_offs(gpio, port));
-+}
-+
-+static int cy8c9540a_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-+{
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, gpio_chip);
-+ return dev->irq_base + gpio;
-+}
-+
-+static int cy8c9540a_irq_set_type(struct irq_data *d, unsigned int type)
-+{
-+ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
-+ int ret = 0;
-+
-+ if ((type != IRQ_TYPE_EDGE_BOTH)) {
-+ dev_err(&dev->client->dev, "irq %d: unsupported type %d\n",
-+ d->irq, type);
-+ ret = -EINVAL;
-+ goto end;
-+ }
-+
-+end:
-+ return ret;
-+}
-+
-+static struct irq_chip cy8c9540a_irq_chip = {
-+ .name = "cy8c9540a-irq",
-+ .irq_mask = cy8c9540a_irq_mask,
-+ .irq_unmask = cy8c9540a_irq_unmask,
-+ .irq_bus_lock = cy8c9540a_irq_bus_lock,
-+ .irq_bus_sync_unlock = cy8c9540a_irq_bus_sync_unlock,
-+ .irq_set_type = cy8c9540a_irq_set_type,
-+};
-+
-+static irqreturn_t cy8c9540a_irq_handler(int irq, void *devid)
-+{
-+ struct cy8c9540a *dev = devid;
-+ u8 stat[NPORTS], pending = 0;
-+ unsigned port = 0, gpio = 0, gpio_irq = 0;
-+ int ret = 0;
-+
-+ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_INTR_STAT_PORT0,
-+ NPORTS, stat); /* W1C */
-+ if (ret < 0) {
-+ memset(stat, 0, sizeof(stat));
-+ }
-+
-+ ret = IRQ_NONE;
-+
-+ for (port = 0; port < NPORTS; port ++) {
-+ /* Databook doesn't specify if this is a post-mask status
-+ register or not. Consider it 'raw' for safety. */
-+ mutex_lock(&dev->irq_lock);
-+ pending = stat[port] & (~dev->irq_mask[port]);
-+ mutex_unlock(&dev->irq_lock);
-+
-+ while (pending) {
-+ ret = IRQ_HANDLED;
-+ gpio = __ffs(pending);
-+ pending &= ~BIT(gpio);
-+ gpio_irq = dev->irq_base + cy8c9540a_port_offs[port]
-+ + gpio;
-+ handle_nested_irq(gpio_irq);
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static int cy8c9540a_irq_setup(struct cy8c9540a *dev)
-+{
-+ struct i2c_client *client = dev->client;
-+ u8 dummy[NPORTS];
-+ unsigned gpio = 0;
-+ int ret = 0;
-+ int i = 0;
-+
-+ mutex_init(&dev->irq_lock);
-+
-+ /* Clear interrupt state */
-+
-+ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_INTR_STAT_PORT0,
-+ NPORTS, dummy); /* W1C */
-+ if (ret < 0) {
-+ dev_err(&client->dev, "couldn't clear int status\n");
-+ goto err;
-+ }
-+
-+ /* Initialise interrupt mask */
-+
-+ memset(dev->irq_mask_cache, 0xff, sizeof(dev->irq_mask_cache));
-+ memset(dev->irq_mask, 0xff, sizeof(dev->irq_mask));
-+ for (i = 0; i < NPORTS; i++) {
-+ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, i);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't select port %u\n", i);
-+ goto err;
-+ }
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_INTR_MASK, dev->irq_mask[i]);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write int mask on port %u\n", i);
-+ goto err;
-+ }
-+ }
-+
-+ /* Allocate IRQ descriptors for Cypress GPIOs and set handler */
-+
-+ ret = irq_alloc_descs(dev->irq_base, dev->irq_base, NGPIO, 0);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "failed to allocate IRQ numbers\n");
-+ goto err;
-+ }
-+
-+ for (gpio = 0; gpio < NGPIO; gpio++) {
-+ int irq = gpio + dev->irq_base;
-+ irq_set_chip_data(irq, dev);
-+ irq_set_chip_and_handler(irq, &cy8c9540a_irq_chip,
-+ handle_edge_irq);
-+ irq_set_nested_thread(irq, 1);
-+ irq_set_noprobe(irq);
-+ }
-+
-+ ret = request_threaded_irq(client->irq, NULL, cy8c9540a_irq_handler,
-+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-+ dev_name(&client->dev), dev);
-+ if (ret) {
-+ dev_err(&client->dev, "failed to request irq %d\n",
-+ client->irq);
-+ goto err_free_irq_descs;
-+ }
-+
-+ return 0;
-+
-+err_free_irq_descs:
-+ irq_free_descs(dev->irq_base, NGPIO);
-+err:
-+ mutex_destroy(&dev->irq_lock);
-+ return ret;
-+}
-+
-+static void cy8c9540a_irq_teardown(struct cy8c9540a *dev)
-+{
-+ struct i2c_client *client = dev->client;
-+
-+ irq_free_descs(dev->irq_base, NGPIO);
-+ free_irq(client->irq, dev);
-+ mutex_destroy(&dev->irq_lock);
-+}
-+
-+static int cy8c9540a_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
-+ int duty_ns, int period_ns)
-+{
-+ int ret = 0;
-+ int period = 0, duty = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, pwm_chip);
-+ struct i2c_client *client = dev->client;
-+
-+ if (pwm->pwm >= CY8C9540A_NPWM) {
-+ return -EINVAL;
-+ }
-+
-+ period = period_ns / PWM_TCLK_NS;
-+ duty = duty_ns / PWM_TCLK_NS;
-+
-+ /*
-+ * Check period's upper bound. Note the duty cycle is already sanity
-+ * checked by the PWM framework.
-+ */
-+ if (period > PWM_MAX_PERIOD) {
-+ dev_err(&client->dev, "period must be within [0-%d]ns\n",
-+ PWM_MAX_PERIOD * PWM_TCLK_NS);
-+ return -EINVAL;
-+ }
-+
-+ mutex_lock(&dev->lock);
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_PWM_SELECT, (u8)pwm->pwm);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write to REG_PWM_SELECT\n");
-+ goto end;
-+ }
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_PWM_PERIOD, (u8)period);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write to REG_PWM_PERIOD\n");
-+ goto end;
-+ }
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_PWM_PULSE_W, (u8)duty);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write to REG_PWM_PULSE_W\n");
-+ goto end;
-+ }
-+
-+end:
-+ mutex_unlock(&dev->lock);
-+
-+ return ret;
-+}
-+
-+static int cy8c9540a_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+ s32 ret = 0;
-+ int gpio = 0;
-+ int port = 0, pin = 0;
-+ u8 out_reg = 0;
-+ u8 val = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, pwm_chip);
-+ struct i2c_client *client = dev->client;
-+
-+ if (pwm->pwm >= CY8C9540A_NPWM) {
-+ return -EINVAL;
-+ }
-+
-+ gpio = dev->pwm2gpio_mapping[pwm->pwm];
-+ port = cypress_get_port(gpio);
-+ pin = cypress_get_offs(gpio, port);
-+ out_reg = REG_OUTPUT_PORT0 + port;
-+
-+ /* Set pin as output driving high */
-+ ret = cy8c9540a_gpio_direction(&dev->gpio_chip, gpio, 1, 1);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't set pwm%u as output\n", pwm->pwm);
-+ return ret;
-+ }
-+
-+ mutex_lock(&dev->lock);
-+
-+ /* Enable PWM */
-+ ret = i2c_smbus_read_byte_data(client, REG_SELECT_PWM);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't read REG_SELECT_PWM\n");
-+ goto end;
-+ }
-+ val = (u8)(ret | BIT((u8)pin));
-+ ret = i2c_smbus_write_byte_data(client, REG_SELECT_PWM, val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write to SELECT_PWM\n");
-+ goto end;
-+ }
-+
-+end:
-+ mutex_unlock(&dev->lock);
-+
-+ return ret;
-+}
-+
-+static void cy8c9540a_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+ s32 ret = 0;
-+ int gpio = 0;
-+ int port = 0, pin = 0;
-+ u8 val = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, pwm_chip);
-+ struct i2c_client *client = dev->client;
-+
-+ if (pwm->pwm >= CY8C9540A_NPWM) {
-+ return;
-+ }
-+
-+ gpio = dev->pwm2gpio_mapping[pwm->pwm];
-+ if (CY8C9540A_PWM_UNUSED == gpio) {
-+ dev_err(&client->dev, "pwm%d is unused\n", pwm->pwm);
-+ return;
-+ }
-+
-+ port = cypress_get_port(gpio);
-+ pin = cypress_get_offs(gpio, port);
-+
-+ mutex_lock(&dev->lock);
-+
-+ /* Disable PWM */
-+ ret = i2c_smbus_read_byte_data(client, REG_SELECT_PWM);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't read REG_SELECT_PWM\n");
-+ goto end;
-+ }
-+ val = (u8)(ret & ~BIT((u8)pin));
-+ ret = i2c_smbus_write_byte_data(client, REG_SELECT_PWM, val);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't write to SELECT_PWM\n");
-+ }
-+
-+end:
-+ mutex_unlock(&dev->lock);
-+
-+ return;
-+}
-+
-+/*
-+ * Some PWMs may be unavailable. Prevent user from reserving them.
-+ */
-+static int cy8c9540a_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
-+{
-+ int gpio = 0;
-+ struct cy8c9540a *dev =
-+ container_of(chip, struct cy8c9540a, pwm_chip);
-+ struct i2c_client *client = dev->client;
-+
-+ if (pwm->pwm >= CY8C9540A_NPWM) {
-+ return -EINVAL;
-+ }
-+
-+ gpio = dev->pwm2gpio_mapping[pwm->pwm];
-+ if (CY8C9540A_PWM_UNUSED == gpio) {
-+ dev_err(&client->dev, "pwm%d unavailable\n", pwm->pwm);
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct pwm_ops cy8c9540a_pwm_ops = {
-+ .request = cy8c9540a_pwm_request,
-+ .config = cy8c9540a_pwm_config,
-+ .enable = cy8c9540a_pwm_enable,
-+ .disable = cy8c9540a_pwm_disable,
-+};
-+
-+/*
-+ * cy8c9540a_set_por_default
-+ *
-+ * Ensure the expander is using platform-specific POR settings.
-+ *
-+ * Note SMBUS max transaction length is 32 bytes, so we have to fall back to
-+ * raw i2c transfers.
-+ */
-+static int cy8c9540a_set_por_default(struct cy8c9540a *dev)
-+{
-+ int ret = 0;
-+ struct i2c_client *client = dev->client;
-+ struct cy8c9540a_pdata *pdata = client->dev.platform_data;
-+ int i = 0;
-+ int segments = -1;
-+ int crc_index = sizeof(por_set) - 1;
-+ u8 reg_cmd_r_por[] = { REG_CMD, CMD_R_EEPROM_POR };
-+
-+ /* Populate platform POR setting table */
-+ memcpy(por_set + POR_CMD_W_OFFS, pdata->por_default,
-+ sizeof(pdata->por_default));
-+
-+ /* Read POR settings stored in EEPROM */
-+ dev->i2c_segments[0].addr = client->addr;
-+ dev->i2c_segments[0].flags = 0; /* write */
-+ dev->i2c_segments[0].len = sizeof(reg_cmd_r_por);
-+ dev->i2c_segments[0].buf = reg_cmd_r_por;
-+ dev->i2c_segments[1].addr = client->addr;
-+ dev->i2c_segments[1].flags = I2C_M_RD;
-+ dev->i2c_segments[1].len = sizeof(dev->por_stored);
-+ dev->i2c_segments[1].buf = dev->por_stored;
-+ segments = 2;
-+ ret = i2c_transfer(client->adapter, dev->i2c_segments, segments);
-+ if (segments != ret) {
-+ dev_err(&client->dev, "can't read POR settings (ret=%d)\n", ret);
-+ goto end;
-+ } else {
-+ ret = 0;
-+ }
-+
-+ /* Compute CRC for platform-defined POR settings */
-+ por_set[crc_index] = 0;
-+ for (i = POR_CMD_W_OFFS; i < crc_index; i ++) {
-+ por_set[crc_index] ^= por_set[i];
-+ }
-+
-+ /* Compare POR settings with platform-defined ones */
-+ for (i = 0; i < sizeof(dev->por_stored); i ++) {
-+ if (dev->por_stored[i] != por_set[i + POR_CMD_W_OFFS]) {
-+ break;
-+ }
-+ }
-+ if (sizeof(dev->por_stored) == i) {
-+ goto end;
-+ }
-+
-+ /* Update POR settings to EEPROM */
-+
-+ dev_info(&client->dev, "updating EEPROM with platform POR settings\n");
-+
-+ /* Store default POR settings into EEPROM */
-+ dev->i2c_segments[0].addr = client->addr;
-+ dev->i2c_segments[0].flags = 0; /* write */
-+ dev->i2c_segments[0].len = sizeof(por_set);
-+ dev->i2c_segments[0].buf = por_set;
-+ segments = 1;
-+ ret = i2c_transfer(client->adapter, dev->i2c_segments, segments);
-+ if (segments != ret) {
-+ dev_err(&client->dev, "can't write POR settings (ret=%d)\n", ret);
-+ goto end;
-+ } else {
-+ ret = 0;
-+ }
-+
-+ /* Reconfigure device with newly stored POR settings */
-+ for (i = 0; i < MAX_RETRIES; i++) {
-+ usleep_range(SLEEP_US_MIN, SLEEP_US_MAX);
-+
-+ ret = i2c_smbus_write_byte_data(client, REG_CMD, CMD_RECONF);
-+ if (0 == ret) {
-+ break;
-+ }
-+ }
-+
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't reconfigure device\n");
-+ }
-+
-+end:
-+ return ret;
-+}
-+
-+/*
-+ * cy8c9540a_setup
-+ *
-+ * Initialise the device with default setup.
-+ * No need to roll back if this fails.
-+ */
-+static int cy8c9540a_setup(struct cy8c9540a *dev)
-+{
-+ int ret = 0;
-+ struct i2c_client *client = dev->client;
-+ const u8 eeprom_enable_seq[] = {0x43, 0x4D, 0x53, 0x2};
-+
-+ /* Test/set platform-specific POR settings */
-+ ret = cy8c9540a_set_por_default(dev);
-+ if (ret) {
-+ dev_err(&client->dev, "can't set POR settings (err=%d)\n", ret);
-+ goto end;
-+ }
-+
-+ /* Cache the output registers */
-+ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_OUTPUT_PORT0,
-+ sizeof(dev->outreg_cache),
-+ dev->outreg_cache);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't cache output registers\n");
-+ goto end;
-+ }
-+
-+ /* Enable the EEPROM */
-+ ret = i2c_smbus_write_i2c_block_data(client, REG_ENABLE,
-+ sizeof(eeprom_enable_seq),
-+ eeprom_enable_seq);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "can't enable EEPROM\n");
-+ goto end;
-+ }
-+
-+end:
-+ return ret;
-+}
-+
-+static int cy8c9540a_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct cy8c9540a *dev;
-+ struct gpio_chip *gc;
-+ struct cy8c9540a_pdata *pdata = client->dev.platform_data;
-+ int ret = 0;
-+ s32 dev_id = 0;
-+
-+ if (NULL == pdata) {
-+ pr_err("%s: platform data is missing\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ if (!i2c_check_functionality(client->adapter,
-+ I2C_FUNC_I2C |
-+ I2C_FUNC_SMBUS_I2C_BLOCK |
-+ I2C_FUNC_SMBUS_BYTE_DATA)) {
-+ dev_err(&client->dev, "i2c adapter doesn't support required "
-+ "functionality\n");
-+ return -EIO;
-+ }
-+
-+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-+ if (dev == NULL) {
-+ dev_err(&client->dev, "failed to alloc memory\n");
-+ return -ENOMEM;
-+ }
-+
-+ dev->client = client;
-+ dev->irq_base = pdata->irq_base;
-+
-+ gc = &dev->gpio_chip;
-+ gc->direction_input = cy8c9540a_gpio_direction_input;
-+ gc->direction_output = cy8c9540a_gpio_direction_output;
-+ gc->get = cy8c9540a_gpio_get_value;
-+ gc->set = cy8c9540a_gpio_set_value;
-+ gc->set_drive = cy8c9540a_gpio_set_drive;
-+
-+ gc->can_sleep = 1;
-+
-+ gc->base = pdata->gpio_base;
-+ gc->ngpio = NGPIO;
-+ gc->label = client->name;
-+ gc->owner = THIS_MODULE;
-+ gc->to_irq = cy8c9540a_gpio_to_irq;
-+
-+ mutex_init(&dev->lock);
-+
-+ /* Whoami */
-+ dev_id = i2c_smbus_read_byte_data(client, REG_DEVID_STAT);
-+ if (dev_id < 0) {
-+ dev_err(&client->dev, "can't read device ID\n");
-+ ret = dev_id;
-+ goto err;
-+ }
-+ dev_info(&client->dev, "dev_id=0x%x\n", dev_id & 0xff);
-+ if (DEVID_FAMILY_CY8C9540A != (dev_id & DEVID_FAMILY_MASK)) {
-+ dev_err(&client->dev, "unknown/unsupported dev_id 0x%x\n",
-+ dev_id & 0xff);
-+ ret = -ENODEV;
-+ goto err;
-+ }
-+
-+ ret = cy8c9540a_setup(dev);
-+ if (ret) {
-+ goto err;
-+ }
-+
-+ ret = cy8c9540a_irq_setup(dev);
-+ if (ret) {
-+ goto err;
-+ }
-+ ret = gpiochip_add(&dev->gpio_chip);
-+ if (ret) {
-+ dev_err(&client->dev, "gpiochip_add failed %d\n", ret);
-+ goto err_irq;
-+ }
-+
-+ dev->pwm_chip.dev = &client->dev;
-+ dev->pwm_chip.ops = &cy8c9540a_pwm_ops;
-+ dev->pwm_chip.base = pdata->pwm_base;
-+ dev->pwm_chip.npwm = CY8C9540A_NPWM;
-+
-+ /* Populate platform-specific PWM-to-GPIO mapping table */
-+ memcpy(dev->pwm2gpio_mapping, pdata->pwm2gpio_mapping, sizeof(pdata->pwm2gpio_mapping));
-+
-+ ret = pwmchip_add(&dev->pwm_chip);
-+ if (ret) {
-+ dev_err(&client->dev, "pwmchip_add failed %d\n", ret);
-+ goto err_gpiochip;
-+ }
-+
-+ i2c_set_clientdata(client, dev);
-+
-+ return 0;
-+
-+err_gpiochip:
-+ if(gpiochip_remove(&dev->gpio_chip))
-+ dev_warn(&client->dev, "gpiochip_remove failed\n");
-+err_irq:
-+ cy8c9540a_irq_teardown(dev);
-+err:
-+ mutex_destroy(&dev->lock);
-+ kfree(dev);
-+
-+ return ret;
-+}
-+
-+static int cy8c9540a_remove(struct i2c_client *client)
-+{
-+ struct cy8c9540a *dev = i2c_get_clientdata(client);
-+ int ret = 0;
-+ int err = 0;
-+
-+ ret = pwmchip_remove(&dev->pwm_chip);
-+ if (ret < 0) {
-+ dev_err(&client->dev, "pwmchip_remove failed %d\n", ret);
-+ err = ret;
-+ }
-+
-+ ret = gpiochip_remove(&dev->gpio_chip);
-+ if (ret) {
-+ dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
-+ err = ret;
-+ }
-+
-+ cy8c9540a_irq_teardown(dev);
-+
-+ mutex_destroy(&dev->lock);
-+ kfree(dev);
-+
-+ return err;
-+}
-+
-+static const struct i2c_device_id cy8c9540a_id[] = {
-+ {DRV_NAME, 0},
-+ {}
-+};
-+
-+MODULE_DEVICE_TABLE(i2c, cy8c9540a_id);
-+
-+static struct i2c_driver cy8c9540a_driver = {
-+ .driver = {
-+ .name = DRV_NAME,
-+ },
-+ .probe = cy8c9540a_probe,
-+ .remove = cy8c9540a_remove,
-+ .id_table = cy8c9540a_id,
-+};
-+
-+module_i2c_driver(cy8c9540a_driver);
-+
-+MODULE_AUTHOR("Josef Ahmad <josef.ahmad@linux.intel.com>");
-+MODULE_DESCRIPTION("GPIO/PWM driver for CY8C9540A I/O expander");
-+MODULE_LICENSE("GPL");
-+
-diff --git a/drivers/mfd/intel_cln_gip.h b/drivers/mfd/intel_cln_gip.h
-new file mode 100644
-index 0000000..80472ae
---- /dev/null
-+++ b/drivers/mfd/intel_cln_gip.h
-@@ -0,0 +1,104 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton GIP (GPIO/I2C) driver
-+ */
-+
-+#ifndef __INTEL_CLNGIP_H__
-+#define __INTEL_CLNGIP_H__
-+
-+#include <linux/i2c.h>
-+#include <linux/mfd/intel_cln_gip_pdata.h>
-+#include <linux/pci.h>
-+#include "../i2c/busses/i2c-designware-core.h"
-+
-+/* PCI BAR for register base address */
-+#define GIP_I2C_BAR 0
-+#define GIP_GPIO_BAR 1
-+
-+/**
-+ * intel_cln_gpio_probe
-+ *
-+ * @param pdev: Pointer to GIP PCI device
-+ * @return 0 success < 0 failure
-+ *
-+ * Perform GPIO-specific probing on behalf of the top-level GIP driver.
-+ */
-+int intel_cln_gpio_probe(struct pci_dev *pdev);
-+
-+/**
-+ * intel_cln_gpio_remove
-+ *
-+ * @param pdev: Pointer to GIP PCI device
-+ *
-+ * Perform GPIO-specific resource release on behalf of the top-level GIP driver.
-+ */
-+void intel_cln_gpio_remove(struct pci_dev *pdev);
-+
-+/**
-+ * intel_cln_gpio_isr
-+ *
-+ * @param irq: IRQ number to be served
-+ * @param dev_id: used to distinguish the device (for shared interrupts)
-+ *
-+ * Perform GPIO-specific ISR of the top-level GIP driver.
-+ */
-+irqreturn_t intel_cln_gpio_isr(int irq, void *dev_id);
-+
-+/**
-+ * intel_cln_gpio_save_state
-+ *
-+ * Save GPIO register state for system-wide suspend events and mask out
-+ * interrupts.
-+ */
-+void intel_cln_gpio_save_state(void);
-+
-+/**
-+ * intel_cln_gpio_restore_state
-+ *
-+ * Restore GPIO register state for system-wide resume events and clear out
-+ * spurious interrupts.
-+ */
-+void intel_cln_gpio_restore_state(void);
-+
-+/**
-+ * intel_cln_i2c_probe
-+ * @param pdev: Pointer to GIP PCI device
-+ * @param drvdata: private driver data
-+ * @param drvdata: GIP platform-specific settings
-+ * @return 0 success < 0 failure
-+ *
-+ * Perform I2C-specific probing on behalf of the top-level GIP driver.
-+ */
-+int intel_cln_i2c_probe(struct pci_dev *pdev,
-+ struct dw_i2c_dev **drvdata,
-+ struct intel_cln_gip_pdata *pdata);
-+
-+/**
-+ * intel_cln_i2c_remove
-+ * @param pdev: Pointer to GIP PCI device
-+ * @param dev: Pointer to I2C private data
-+ *
-+ * Perform I2C-specific resource release on behalf of the top-level GIP driver.
-+ */
-+void intel_cln_i2c_remove(struct pci_dev *pdev,
-+ struct dw_i2c_dev *dev);
-+
-+#endif /* __INTEL_CLNGIP_H__ */
-diff --git a/drivers/mfd/intel_cln_gip_core.c b/drivers/mfd/intel_cln_gip_core.c
-new file mode 100644
-index 0000000..24f175d
---- /dev/null
-+++ b/drivers/mfd/intel_cln_gip_core.c
-@@ -0,0 +1,335 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton GIP (GPIO/I2C) PCI driver
-+ *
-+ * PCI glue logic for Clanton GIP driver.
-+ * Clanton GIP is a single PCI function exporting a GPIO and an I2C device.
-+ * The PCI driver performs the bus-dependent probe/release operations, and
-+ * call into GPIO/I2C specific modules for handling the two diffrerent
-+ * functionalities.
-+ */
-+
-+#include <asm/cln.h>
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/i2c.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/kernel.h>
-+#include <linux/mfd/intel_cln_gip_pdata.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include "intel_cln_gip.h"
-+
-+static unsigned int enable_msi = 1;
-+module_param(enable_msi, uint, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
-+
-+static unsigned int i2c = 1;
-+module_param(i2c, uint, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(i2c, "Register I2C adapter");
-+
-+static unsigned int gpio = 1;
-+module_param(gpio, uint, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(gpio, "Register GPIO chip");
-+
-+/* GIP private data, supporting only a single instance of the device. */
-+struct intel_cln_gip_data {
-+ struct pci_dev *pci_device;
-+ struct dw_i2c_dev *i2c_drvdata;
-+ struct intel_cln_gip_pdata *pdata;
-+};
-+
-+/**
-+ * intel_cln_gip_handler
-+ *
-+ * @param irq: IRQ number to be served
-+ * @param dev_id: device private data
-+ *
-+ * Top-level interrupt handler for GIP driver.
-+ * It calls into the appropriate sub-routines and gathers the return values.
-+ */
-+static irqreturn_t intel_cln_gip_handler(int irq, void *dev_id)
-+{
-+ irqreturn_t ret_i2c = IRQ_NONE;
-+ irqreturn_t ret_gpio = IRQ_NONE;
-+ struct intel_cln_gip_data *data = (struct intel_cln_gip_data *)dev_id;
-+
-+ mask_pvm(data->pci_device);
-+
-+ if (likely(i2c)) {
-+ /* Only I2C gets platform data */
-+ ret_i2c = i2c_dw_isr(irq, data->i2c_drvdata);
-+ }
-+
-+ if (likely(gpio)) {
-+ ret_gpio = intel_cln_gpio_isr(irq, NULL);
-+ }
-+
-+ unmask_pvm(data->pci_device);
-+
-+ if (likely(IRQ_HANDLED == ret_i2c || IRQ_HANDLED == ret_gpio))
-+ return IRQ_HANDLED;
-+
-+ /* Each sub-ISR routine returns either IRQ_HANDLED or IRQ_NONE. */
-+ return IRQ_NONE;
-+}
-+
-+static DEFINE_PCI_DEVICE_TABLE(intel_cln_gip_ids) = {
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0934), },
-+ { 0, }
-+};
-+MODULE_DEVICE_TABLE(pci, intel_cln_gip_ids);
-+
-+#ifdef CONFIG_PM
-+
-+/**
-+ * cln_gip_suspend
-+ *
-+ * @param device: Pointer to device
-+ * @return 0 success < 0 failure
-+ *
-+ * Prepare GIP for system-wide transition to sleep state.
-+ * Save context, disable GPIO chip and I2C adapter, transition PCI device into
-+ * low-power state.
-+ */
-+static int cln_gip_suspend(struct device *dev)
-+{
-+ int err = 0;
-+ struct intel_cln_gip_data *data = NULL;
-+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
-+ data = (struct intel_cln_gip_data *)pci_get_drvdata(pdev);
-+
-+ i2c_dw_disable(data->i2c_drvdata);
-+ intel_cln_gpio_save_state();
-+
-+ err = pci_save_state(pdev);
-+ if (err) {
-+ dev_err(&pdev->dev, "pci_save_state failed\n");
-+ return err;
-+ }
-+
-+ err = pci_set_power_state(pdev, PCI_D3hot);
-+ if (err) {
-+ dev_err(&pdev->dev, "pci_set_power_state failed\n");
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * cln_gip_resume
-+ *
-+ * @param device: Pointer to device
-+ * @return 0 success < 0 failure
-+ *
-+ * Prepare GIP for system-wide transition to fully active state.
-+ * Set PCI device into full-power state, restore context, enable I2C adapter
-+ * and GPIO chip.
-+ */
-+static int cln_gip_resume(struct device *dev)
-+{
-+ int err = 0;
-+ struct intel_cln_gip_data *data = NULL;
-+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
-+ data = (struct intel_cln_gip_data *)pci_get_drvdata(pdev);
-+
-+ err = pci_set_power_state(pdev, PCI_D0);
-+ if (err) {
-+ dev_err(&pdev->dev, "pci_set_power_state() failed\n");
-+ return err;
-+ }
-+
-+ pci_restore_state(pdev);
-+
-+ intel_cln_gpio_restore_state();
-+ i2c_dw_init(data->i2c_drvdata);
-+
-+ return 0;
-+}
-+
-+#else
-+#define cln_gip_suspend NULL
-+#define cln_gip_resume NULL
-+#endif
-+
-+static const struct dev_pm_ops cln_gip_pm_ops = {
-+ .resume = cln_gip_resume,
-+ .suspend = cln_gip_suspend,
-+};
-+
-+/**
-+ * intel_cln_gip_probe
-+ *
-+ * @param pdev: Pointer to GIP PCI device
-+ * @param id: GIP PCI Device ID
-+ * @return 0 success < 0 failure
-+ *
-+ * GIP PCI driver probing. Calls into the appropriate probe routines for GPIO
-+ * and I2C too.
-+ */
-+static int intel_cln_gip_probe(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
-+{
-+ int retval = 0;
-+ struct intel_cln_gip_data *gip_drvdata = NULL;
-+
-+ retval = pci_enable_device(pdev);
-+ if (retval)
-+ return retval;
-+
-+ retval = pci_request_regions(pdev, "cln-gip");
-+ if (retval) {
-+ dev_err(&pdev->dev, "error requesting PCI region\n");
-+ goto err_pcidev_disable;
-+ }
-+
-+ gip_drvdata = kzalloc(sizeof(struct intel_cln_gip_data), GFP_KERNEL);
-+ if (NULL == gip_drvdata) {
-+ retval = -ENOMEM;
-+ goto err_pciregions_release;
-+ }
-+ pci_set_drvdata(pdev, gip_drvdata);
-+
-+ gip_drvdata->pci_device = pdev;
-+
-+ /* Retrieve platform data if there is any */
-+ if (*intel_cln_gip_get_pdata) {
-+ gip_drvdata->pdata = intel_cln_gip_get_pdata();
-+ }
-+
-+ if (gpio) {
-+ retval = intel_cln_gpio_probe(pdev);
-+ if (retval)
-+ goto err_release_drvdata;
-+ }
-+
-+ if (i2c) {
-+ retval = intel_cln_i2c_probe(pdev,
-+ (struct dw_i2c_dev **)&gip_drvdata->i2c_drvdata,
-+ gip_drvdata->pdata);
-+ if (retval)
-+ goto err_release_drvdata;
-+ }
-+
-+ if (enable_msi) {
-+ pci_set_master(pdev);
-+ retval = pci_enable_msi(pdev);
-+ if (retval)
-+ goto err_release_drvdata;
-+ }
-+
-+ /*
-+ * Request a shared IRQ.
-+ * Since the dev_id cannot be NULL, it points to PCI device descriptor
-+ * if I2C is not registered.
-+ */
-+ retval = request_irq(pdev->irq, intel_cln_gip_handler, IRQF_SHARED,
-+ "intel_cln_gip", gip_drvdata);
-+ if (retval) {
-+ dev_err(&pdev->dev, "error requesting IRQ\n");
-+ goto err;
-+ }
-+
-+ return 0;
-+
-+err_release_drvdata:
-+ pci_set_drvdata(pdev, NULL);
-+ kfree(gip_drvdata);
-+err:
-+ if (enable_msi)
-+ pci_disable_msi(pdev);
-+err_pciregions_release:
-+ pci_release_regions(pdev);
-+err_pcidev_disable:
-+ pci_disable_device(pdev);
-+
-+ return retval;
-+}
-+
-+/**
-+ * intel_cln_gip_remove
-+ *
-+ * @param pdev: Pointer to GIP PCI device
-+ *
-+ * Release resources. Calls into GPIO/I2C dedicate routines too.
-+ */
-+static void intel_cln_gip_remove(struct pci_dev *pdev)
-+{
-+ struct intel_cln_gip_data *data = NULL;
-+
-+ data = (struct intel_cln_gip_data *)pci_get_drvdata(pdev);
-+
-+ if (NULL == data) {
-+ dev_err(&pdev->dev, "%s: failure getting driver data\n",
-+ __func__);
-+ return;
-+ }
-+
-+ free_irq(pdev->irq, data);
-+
-+ if (enable_msi) {
-+ pci_clear_master(pdev);
-+ if (pci_dev_msi_enabled(pdev))
-+ pci_disable_msi(pdev);
-+ }
-+
-+ if (i2c)
-+ intel_cln_i2c_remove(pdev, data->i2c_drvdata);
-+
-+ if (gpio)
-+ intel_cln_gpio_remove(pdev);
-+
-+ pci_set_drvdata(pdev, NULL);
-+ kfree(data);
-+
-+ pci_release_regions(pdev);
-+ pci_disable_device(pdev);
-+}
-+
-+static struct pci_driver intel_cln_gip_driver = {
-+ .name = "intel_cln_gip",
-+ .id_table = intel_cln_gip_ids,
-+ .probe = intel_cln_gip_probe,
-+ .remove = intel_cln_gip_remove,
-+ .driver = {
-+ .pm = &cln_gip_pm_ops,
-+ },
-+};
-+
-+static int intel_cln_gip_init(void)
-+{
-+ return pci_register_driver(&intel_cln_gip_driver);
-+}
-+
-+static void intel_cln_gip_exit(void)
-+{
-+ pci_unregister_driver(&intel_cln_gip_driver);
-+}
-+
-+module_init(intel_cln_gip_init);
-+module_exit(intel_cln_gip_exit);
-+
-+MODULE_AUTHOR("Intel Corporation");
-+MODULE_DESCRIPTION("Clanton GIP driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/mfd/intel_cln_gip_gpio.c b/drivers/mfd/intel_cln_gip_gpio.c
-new file mode 100644
-index 0000000..6e2bbbf
---- /dev/null
-+++ b/drivers/mfd/intel_cln_gip_gpio.c
-@@ -0,0 +1,660 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton GIP (GPIO/I2C) - GPIO-specific PCI and core driver
-+ *
-+ * PCI glue logic and core driver for Clanton GIP/GPIO.
-+ * The GIP GPIO device is the DesignWare GPIO. This file defines the PCI glue
-+ * for this driver and as well as the core logic for the device.
-+ * Please note only a single instance of the GPIO device is supported.
-+ * The default number of GPIO is 8, all interrupt-capable.
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/irq.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/platform_device.h>
-+#include <linux/uio_driver.h>
-+#include "intel_cln_gip.h"
-+
-+static void cln_gpio_restrict_release(struct device *dev) {}
-+static struct platform_device cln_gpio_restrict_pdev =
-+{
-+ .name = "cln-gpio-restrict-sc",
-+ .dev.release = cln_gpio_restrict_release,
-+};
-+struct uio_info *info;
-+
-+/* The base GPIO number under GPIOLIB framework */
-+#define INTEL_CLN_GIP_GPIO_BASE 8
-+
-+/* The default number of South-Cluster GPIO on Clanton. */
-+#define INTEL_CLN_GIP_NGPIO 8
-+
-+/*
-+ * The default base IRQ for searching and allocating the range of GPIO IRQ
-+ * descriptors.
-+ */
-+#define INTEL_CLN_GIP_GPIO_IRQBASE 56
-+
-+/* The GPIO private data. */
-+static struct gpio_chip *gc;
-+static struct irq_chip_generic *igc;
-+static void __iomem *reg_base;
-+static spinlock_t lock;
-+static int irq_base;
-+static unsigned int n_gpio = INTEL_CLN_GIP_NGPIO;
-+static unsigned int gpio_irqbase = INTEL_CLN_GIP_GPIO_IRQBASE;
-+
-+/* Store GPIO context across system-wide suspend/resume transitions */
-+static struct gpio_saved_regs {
-+ u32 data;
-+ u32 dir;
-+ u32 int_en;
-+ u32 int_mask;
-+ u32 int_type;
-+ u32 int_pol;
-+ u32 int_deb;
-+} saved_regs;
-+
-+/* PortA registers set. Note other ports are unused */
-+#define PORTA_DATA 0x00 /* Data */
-+#define PORTA_DIR 0x04 /* Direction */
-+#define PORTA_INT_EN 0x30 /* Interrupt enable */
-+#define PORTA_INT_MASK 0x34 /* Interrupt mask */
-+#define PORTA_INT_TYPE_LEVEL 0x38 /* Interrupt level*/
-+#define PORTA_INT_POLARITY 0x3c /* Interrupt polarity */
-+#define PORTA_INT_STATUS 0x40 /* Interrupt status */
-+#define PORTA_INT_RAW_STATUS 0x44 /* Interrupt raw status */
-+#define PORTA_DEBOUNCE 0x48 /* Debounce enable */
-+#define PORTA_INT_EOI 0x4c /* Clear interrupt */
-+#define PORTA_EXT 0x50 /* External */
-+
-+module_param(n_gpio, uint, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(n_gpio, "Number of GPIO");
-+
-+module_param(gpio_irqbase, uint, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(gpio_irqbase, "Base IRQ for GPIO range");
-+
-+/**
-+ * intel_cln_gpio_get
-+ * @param chip: Pointer to GPIO chip registered by GPIOLIB
-+ * @param offset: the GPIO number within the GPIOLIB chip
-+ * @return 0 if GPIO is deasserted, 1 if GPIO is asserted
-+ *
-+ * Read back the value of a GPIO.
-+ */
-+static int intel_cln_gpio_get(struct gpio_chip *chip, unsigned offset)
-+{
-+ void __iomem *reg_ext = reg_base + PORTA_EXT;
-+ u32 val_ext = ioread32(reg_ext);
-+
-+ val_ext &= BIT(offset % 32);
-+ return (val_ext > 0);
-+}
-+
-+/**
-+ * intel_cln_gpio_set
-+ * @param chip: Pointer to GPIO chip registered by GPIOLIB
-+ * @param offset: the GPIO number within the GPIOLIB chip
-+ *
-+ * Set value of a GPIO.
-+ */
-+static void intel_cln_gpio_set(struct gpio_chip *chip, unsigned offset,
-+ int value)
-+{
-+ void __iomem *reg_data = reg_base + PORTA_DATA;
-+ u32 val_data = 0;
-+ unsigned long flags = 0;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ val_data = ioread32(reg_data);
-+ if (value)
-+ iowrite32(val_data | BIT(offset % 32), reg_data);
-+ else
-+ iowrite32(val_data & ~BIT(offset % 32), reg_data);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_direction_input
-+ * @param chip: Pointer to GPIO chip registered by GPIOLIB
-+ * @param offset: the GPIO number within the GPIOLIB chip
-+ * @return always 0 (success)
-+ *
-+ * Set direction of a GPIO as input.
-+ */
-+static int intel_cln_gpio_direction_input(struct gpio_chip *chip,
-+ unsigned offset)
-+{
-+ u32 val_dir = 0;
-+ void __iomem *reg_dir = reg_base + PORTA_DIR;
-+ unsigned long flags = 0;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ val_dir = ioread32(reg_dir);
-+ iowrite32(val_dir & ~BIT(offset % 32), reg_dir);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_gpio_direction_output
-+ * @param chip: Pointer to GPIO chip registered by GPIOLIB
-+ * @param offset: the GPIO number within the GPIOLIB chip
-+ * @param value: value to be driven to the GPIO
-+ * @return always 0 (success)
-+ *
-+ * Set the default value of a GPIO, and then set direction as output.
-+ */
-+static int intel_cln_gpio_direction_output(struct gpio_chip *chip,
-+ unsigned offset, int value)
-+{
-+ u32 val_dir = 0;
-+ void __iomem *reg_dir = reg_base + PORTA_DIR;
-+ unsigned long flags = 0;
-+
-+ /* Ensure glitch-free operation. */
-+ intel_cln_gpio_set(chip, offset, value);
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ val_dir = ioread32(reg_dir);
-+ iowrite32(val_dir | BIT(offset % 32), reg_dir);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_gpio_set_debounce
-+ * @param chip: Pointer to GPIO chip registered by GPIOLIB
-+ * @param offset: the GPIO number within the GPIOLIB chip
-+ * @param debounce: 1 to enable, 0 to disable
-+ * @return always 0 (success)
-+ *
-+ * Enable/disable interrupt debounce logic for a GPIO.
-+ */
-+static int intel_cln_gpio_set_debounce(struct gpio_chip *chip,
-+ unsigned offset, unsigned debounce)
-+{
-+ u32 val_deb = 0;
-+ void __iomem *reg_deb = reg_base + PORTA_DEBOUNCE;
-+ unsigned long flags = 0;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ val_deb = ioread32(reg_deb);
-+ if (debounce)
-+ iowrite32(val_deb | BIT(offset % 32), reg_deb);
-+ else
-+ iowrite32(val_deb & ~BIT(offset % 32), reg_deb);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_gpio_irq_type
-+ * @param irq_data: Pointer to information about the IRQ
-+ * @param type: set the triggering type of the interrupt
-+ * @return always 0 (success)
-+ *
-+ * Set interrupt triggering type for a GPIO.
-+ */
-+static int intel_cln_gpio_irq_type(struct irq_data *d, unsigned type)
-+{
-+ int ret = 0;
-+ unsigned long flags = 0;
-+ void __iomem *reg_level = reg_base + PORTA_INT_TYPE_LEVEL;
-+ void __iomem *reg_pol = reg_base + PORTA_INT_POLARITY;
-+ u32 val_level = 0;
-+ u32 val_pol = 0;
-+ u32 gpio = 0;
-+
-+ if (NULL == d) {
-+ pr_err("%s(): null irq_data\n", __func__);
-+ return -EFAULT;
-+ }
-+
-+ gpio = d->irq - irq_base;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ val_level = ioread32(reg_level);
-+ val_pol = ioread32(reg_pol);
-+
-+ switch (type) {
-+ case IRQ_TYPE_EDGE_RISING:
-+ iowrite32(val_level | BIT(gpio % 32), reg_level);
-+ iowrite32(val_pol | BIT(gpio % 32), reg_pol);
-+ break;
-+ case IRQ_TYPE_EDGE_FALLING:
-+ iowrite32(val_level | BIT(gpio % 32), reg_level);
-+ iowrite32(val_pol & ~BIT(gpio % 32), reg_pol);
-+ break;
-+ case IRQ_TYPE_LEVEL_HIGH:
-+ iowrite32(val_level & ~BIT(gpio % 32), reg_level);
-+ iowrite32(val_pol | BIT(gpio % 32), reg_pol);
-+ break;
-+ case IRQ_TYPE_LEVEL_LOW:
-+ iowrite32(val_level & ~BIT(gpio % 32), reg_level);
-+ iowrite32(val_pol & ~BIT(gpio % 32), reg_pol);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+
-+ return ret;
-+}
-+
-+/**
-+ * intel_cln_gpio_irq_unmask
-+ * @param irq_data: Pointer to information about the IRQ
-+ *
-+ * Unmask interrupts for a GPIO.
-+ */
-+static void intel_cln_gpio_irq_unmask(struct irq_data *d)
-+{
-+ unsigned long flags = 0;
-+ void __iomem *reg_mask = reg_base + PORTA_INT_MASK;
-+ u32 val_mask = 0;
-+ unsigned gpio = 0;
-+
-+ if (NULL == d) {
-+ pr_err("%s(): null irq_data\n", __func__);
-+ return;
-+ }
-+
-+ gpio = d->irq - irq_base;
-+
-+ spin_lock_irqsave(&lock, flags);
-+ val_mask = ioread32(reg_mask);
-+ iowrite32(val_mask | BIT(gpio % 32), reg_mask);
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_irq_mask
-+ * @param irq_data: Pointer to information about the IRQ
-+ *
-+ * Mask interrupts for a GPIO.
-+ */
-+static void intel_cln_gpio_irq_mask(struct irq_data *d)
-+{
-+ unsigned long flags = 0;
-+ void __iomem *reg_mask = reg_base + PORTA_INT_MASK;
-+ u32 val_mask = 0;
-+ unsigned gpio = 0;
-+
-+ if (NULL == d) {
-+ pr_err("%s(): null irq_data\n", __func__);
-+ return;
-+ }
-+
-+ gpio = d->irq - irq_base;
-+
-+ spin_lock_irqsave(&lock, flags);
-+ val_mask = ioread32(reg_mask);
-+ iowrite32(val_mask & ~BIT(gpio % 32), reg_mask);
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_irq_enable
-+ * @param irq_data: Pointer to information about the IRQ
-+ *
-+ * Enable interrupts for a GPIO.
-+ */
-+static void intel_cln_gpio_irq_enable(struct irq_data *d)
-+{
-+ unsigned long flags = 0;
-+ void __iomem *reg_inte = reg_base + PORTA_INT_EN;
-+ u32 val_inte = 0;
-+ unsigned gpio = 0;
-+
-+ if (NULL == d) {
-+ pr_err("%s(): null irq_data\n", __func__);
-+ return;
-+ }
-+
-+ gpio = d->irq - irq_base;
-+
-+ spin_lock_irqsave(&lock, flags);
-+ val_inte = ioread32(reg_inte);
-+ iowrite32(val_inte | BIT(gpio % 32), reg_inte);
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_irq_disable
-+ * @param irq_data: Pointer to information about the IRQ
-+ *
-+ * Disable interrupts for a GPIO.
-+ */
-+static void intel_cln_gpio_irq_disable(struct irq_data *d)
-+{
-+ unsigned long flags = 0;
-+ void __iomem *reg_inte = reg_base + PORTA_INT_EN;
-+ u32 val_inte = 0;
-+ unsigned gpio = 0;
-+
-+ if (NULL == d) {
-+ pr_err("%s(): null irq_data\n", __func__);
-+ return;
-+ }
-+
-+ gpio = d->irq - irq_base;
-+
-+ spin_lock_irqsave(&lock, flags);
-+ val_inte = ioread32(reg_inte);
-+ iowrite32(val_inte & ~BIT(gpio % 32), reg_inte);
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_to_irq
-+ * @param chip: Pointer to GPIO chip registered by GPIOLIB
-+ * @param offset: the GPIO number within the GPIOLIB chip
-+ * @return IRQ associated to GPIO
-+ *
-+ * Compute the IRQ number based on the GPIO.
-+ */
-+static int intel_cln_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-+{
-+ return irq_base + offset;
-+}
-+
-+/**
-+ * intel_cln_gpio_isr
-+ * @param irq: IRQ number
-+ * @param dev_id: cookie used to tell what instance of the driver the interrupt
-+ * belongs to
-+ * @return IRQ_HANDLED if interrupt served, IRQ_NONE if no interrupt pending
-+ *
-+ * Interrupt Service Routine for GPIO. Identify which GPIOs (if any) is pending
-+ * for interrupt to be served, acknowledge the interrupt and serve it.
-+ */
-+irqreturn_t intel_cln_gpio_isr(int irq, void *dev_id)
-+{
-+ irqreturn_t ret = IRQ_NONE;
-+ u32 pending = 0, gpio = 0;
-+ void __iomem *reg_pending = reg_base + PORTA_INT_STATUS;
-+ void __iomem *reg_eoi = reg_base + PORTA_INT_EOI;
-+
-+ /* Which pin (if any) triggered the interrupt */
-+ while ((pending = ioread32(reg_pending))) {
-+ /*
-+ * Acknowledge all the asserted GPIO interrupt lines before
-+ * serving them, so that we don't lose an edge.
-+ * This has only effect on edge-triggered interrupts.
-+ */
-+ iowrite32(pending, reg_eoi);
-+
-+ /* Serve each asserted interrupt */
-+ do {
-+ gpio = __ffs(pending);
-+ generic_handle_irq(
-+ gpio_to_irq(INTEL_CLN_GIP_GPIO_BASE + gpio));
-+ pending &= ~BIT(gpio);
-+ ret = IRQ_HANDLED;
-+ } while(pending);
-+ }
-+
-+ return ret;
-+}
-+
-+/**
-+ * intel_cln_gpio_save_state
-+ *
-+ * Save GPIO register state for system-wide suspend events and mask out
-+ * interrupts.
-+ */
-+void intel_cln_gpio_save_state(void)
-+{
-+ unsigned long flags = 0;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ saved_regs.int_mask = ioread32(reg_base + PORTA_INT_MASK);
-+ saved_regs.int_en = ioread32(reg_base + PORTA_INT_EN);
-+ saved_regs.int_deb = ioread32(reg_base + PORTA_DEBOUNCE);
-+ saved_regs.int_pol = ioread32(reg_base + PORTA_INT_POLARITY);
-+ saved_regs.int_type = ioread32(reg_base + PORTA_INT_TYPE_LEVEL);
-+ saved_regs.dir = ioread32(reg_base + PORTA_DIR);
-+ saved_regs.data = ioread32(reg_base + PORTA_DATA);
-+
-+ /* Mask out interrupts */
-+ iowrite32(0xffffffff, reg_base + PORTA_INT_MASK);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_restore_state
-+ *
-+ * Restore GPIO register state for system-wide resume events and clear out
-+ * spurious interrupts.
-+ */
-+void intel_cln_gpio_restore_state(void)
-+{
-+ unsigned long flags = 0;
-+
-+ spin_lock_irqsave(&lock, flags);
-+
-+ iowrite32(saved_regs.data, reg_base + PORTA_DATA);
-+ iowrite32(saved_regs.dir, reg_base + PORTA_DIR);
-+ iowrite32(saved_regs.int_type, reg_base + PORTA_INT_TYPE_LEVEL);
-+ iowrite32(saved_regs.int_pol, reg_base + PORTA_INT_POLARITY);
-+ iowrite32(saved_regs.int_deb, reg_base + PORTA_DEBOUNCE);
-+ iowrite32(saved_regs.int_en, reg_base + PORTA_INT_EN);
-+ iowrite32(saved_regs.int_mask, reg_base + PORTA_INT_MASK);
-+
-+ /* Clear out spurious interrupts */
-+ iowrite32(0xffffffff, reg_base + PORTA_INT_EOI);
-+
-+ spin_unlock_irqrestore(&lock, flags);
-+}
-+
-+/**
-+ * intel_cln_gpio_probe
-+ * @param pdev: Pointer to GIP PCI device
-+ * @return 0 success < 0 failure
-+ *
-+ * Perform GPIO-specific probing on behalf of the top-level GIP driver.
-+ * Initiate the GPIO device.
-+ */
-+int intel_cln_gpio_probe(struct pci_dev *pdev)
-+{
-+ int retval = 0;
-+ resource_size_t start = 0, len = 0;
-+
-+ /* Get UIO memory */
-+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
-+ if (!info)
-+ return -ENOMEM;
-+
-+ /* Determine the address of the GPIO area */
-+ start = pci_resource_start(pdev, GIP_GPIO_BAR);
-+ len = pci_resource_len(pdev, GIP_GPIO_BAR);
-+ if (!start || len == 0) {
-+ dev_err(&pdev->dev, "bar%d not set\n", GIP_GPIO_BAR);
-+ retval = -ENODEV;
-+ goto exit;
-+ }
-+
-+ reg_base = ioremap_nocache(start, len);
-+ if (NULL == reg_base) {
-+ dev_err(&pdev->dev, "I/O memory remapping failed\n");
-+ retval = -EFAULT;
-+ goto exit;
-+ }
-+
-+ memset(&saved_regs, 0x0, sizeof(saved_regs));
-+
-+ gc = kzalloc(sizeof(struct gpio_chip), GFP_KERNEL);
-+ if (!gc) {
-+ retval = -ENOMEM;
-+ goto err_iounmap;
-+ }
-+
-+ if (n_gpio == 0 || n_gpio > INTEL_CLN_GIP_NGPIO) {
-+ dev_err(&pdev->dev, "n_gpio outside range [1,%d]\n",
-+ INTEL_CLN_GIP_NGPIO);
-+ retval = -EINVAL;
-+ goto err_free_gpiochip;
-+ }
-+
-+ gc->label = "intel_cln_gip_gpio";
-+ gc->owner = THIS_MODULE;
-+ gc->direction_input = intel_cln_gpio_direction_input;
-+ gc->direction_output = intel_cln_gpio_direction_output;
-+ gc->get = intel_cln_gpio_get;
-+ gc->set = intel_cln_gpio_set;
-+ gc->set_debounce = intel_cln_gpio_set_debounce;
-+ gc->to_irq = intel_cln_gpio_to_irq;
-+ gc->base = INTEL_CLN_GIP_GPIO_BASE;
-+ gc->ngpio = n_gpio;
-+ gc->can_sleep = 0;
-+ retval = gpiochip_add(gc);
-+ if (retval) {
-+ dev_err(&pdev->dev, "failure adding GPIO chip\n");
-+ goto err_free_gpiochip;
-+ }
-+
-+ spin_lock_init(&lock);
-+
-+ /*
-+ * Allocate a range of IRQ descriptor for the available GPIO.
-+ * IRQs are allocated dynamically.
-+ */
-+ irq_base = irq_alloc_descs(-1, gpio_irqbase, n_gpio, NUMA_NO_NODE);
-+ if (irq_base < 0) {
-+ dev_err(&pdev->dev, "failure adding GPIO IRQ descriptors\n");
-+ goto err_remove_gpiochip;
-+ }
-+
-+ retval = platform_device_register(&cln_gpio_restrict_pdev);
-+ if (retval < 0){
-+ goto err_free_irq_descs;
-+ }
-+
-+ igc = irq_alloc_generic_chip("intel_cln_gip_gpio", 1, irq_base,
-+ reg_base, handle_simple_irq);
-+ if (NULL == igc) {
-+ retval = -ENOMEM;
-+ goto err_free_irq_descs;
-+ }
-+
-+ /* UIO */
-+ info->mem[0].addr = start;
-+ info->mem[0].internal_addr = reg_base;
-+ info->mem[0].size = len;
-+ info->mem[0].memtype = UIO_MEM_PHYS;
-+ info->mem[0].name = "gpio_regs";
-+ info->name = "gpio uio";
-+ info->version = "0.0.1";
-+
-+ if (uio_register_device(&pdev->dev, info))
-+ goto err_free_irq_descs;
-+
-+ pr_info("%s UIO addr 0x%08x internal_addr 0x%08x size %lu memtype %d\n",
-+ __func__, (unsigned int)info->mem[0].addr,
-+ (unsigned int)info->mem[0].internal_addr, info->mem[0].size,
-+ info->mem[0].memtype);
-+ igc->chip_types->chip.irq_mask = intel_cln_gpio_irq_mask;
-+ igc->chip_types->chip.irq_unmask = intel_cln_gpio_irq_unmask;
-+ igc->chip_types->chip.irq_set_type = intel_cln_gpio_irq_type;
-+ igc->chip_types->chip.irq_enable = intel_cln_gpio_irq_enable;
-+ igc->chip_types->chip.irq_disable = intel_cln_gpio_irq_disable;
-+
-+ irq_setup_generic_chip(igc, IRQ_MSK(n_gpio), IRQ_GC_INIT_MASK_CACHE,
-+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
-+
-+ return 0;
-+
-+err_free_irq_descs:
-+ irq_free_descs(irq_base, n_gpio);
-+err_remove_gpiochip:
-+ if (0 != gpiochip_remove(gc))
-+ dev_err(&pdev->dev, "failed removing gpio_chip\n");
-+err_free_gpiochip:
-+ kfree(gc);
-+err_iounmap:
-+ iounmap(reg_base);
-+exit:
-+ if (info != NULL)
-+ kfree(info);
-+ return retval;
-+}
-+
-+/**
-+ * intel_cln_gpio_remove
-+ * @param pdev: Pointer to GIP PCI device
-+ *
-+ * Perform GPIO-specific resource release on behalf of the top-level GIP
-+ * driver.
-+ */
-+void intel_cln_gpio_remove(struct pci_dev *pdev)
-+{
-+ if (NULL == igc) {
-+ dev_err(&pdev->dev, "null pointer to irq_generic_chip\n");
-+ return;
-+ }
-+ if (NULL == gc) {
-+ dev_err(&pdev->dev, "null pointer to gpio_chip\n");
-+ return;
-+ }
-+
-+ /* Tear down IRQ descriptors */
-+ irq_remove_generic_chip(igc, IRQ_MSK(n_gpio), 0,
-+ IRQ_NOREQUEST | IRQ_NOPROBE);
-+ kfree(igc);
-+ irq_free_descs(irq_base, n_gpio);
-+
-+ platform_device_unregister(&cln_gpio_restrict_pdev);
-+
-+ /* Release GPIO chip */
-+ if (0 != gpiochip_remove(gc))
-+ dev_err(&pdev->dev, "failed removing gpio_chip\n");
-+
-+
-+ if (info != NULL){
-+ uio_unregister_device(info);
-+ iounmap(info->mem[0].internal_addr);
-+ kfree(info);
-+ }
-+
-+ kfree(gc);
-+ iounmap(reg_base);
-+}
-diff --git a/drivers/mfd/intel_cln_gip_i2c.c b/drivers/mfd/intel_cln_gip_i2c.c
-new file mode 100644
-index 0000000..279ebb3
---- /dev/null
-+++ b/drivers/mfd/intel_cln_gip_i2c.c
-@@ -0,0 +1,248 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton GIP (GPIO/I2C) - I2C-specific PCI driver
-+ *
-+ * PCI glue logic for Clanton GIP/I2C.
-+ * The GIP I2C device is the DesignWare I2C. This file defines the PCI glue
-+ * for this driver and is heavily based on
-+ * on drivers/i2c/busses/i2c-designware-pcidrv.c. Also, it relies on
-+ * drivers/i2c/busses/i2c-designware-core.c for the core logic.
-+ * Please note only a single instance of the I2C device is supported.
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/i2c.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include "intel_cln_gip.h"
-+
-+enum dw_pci_ctl_id_t {
-+ clanton_0,
-+};
-+
-+/*
-+ * By default, driver operates in fast mode (400kHz).
-+ *
-+ * Standard mode operation (100kHz) can be forced via, in order of priority:
-+ * 1. setting the following i2c_std_mode module parameter to 1
-+ * 2. setting the platform data i2c_std_mode parameter to 1
-+ *
-+ * Note in both cases, setting i2c_std_mode to 0 means forcing fast mode
-+ * operation.
-+ */
-+static unsigned int i2c_std_mode = -1;
-+module_param(i2c_std_mode, uint, S_IRUSR);
-+MODULE_PARM_DESC(i2c_std_mode, "Set to 1 to force I2C standard mode");
-+
-+#define INTEL_CLN_STD_CFG (DW_IC_CON_MASTER | \
-+ DW_IC_CON_SLAVE_DISABLE | \
-+ DW_IC_CON_RESTART_EN)
-+
-+static struct dw_pci_controller cln_gip_i2c_controller = {
-+ .bus_num = 0,
-+ .bus_cfg = INTEL_CLN_STD_CFG | DW_IC_CON_SPEED_FAST,
-+ .tx_fifo_depth = 16,
-+ .rx_fifo_depth = 16,
-+ .clk_khz =
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
-+ 14000,
-+#else
-+ 33000,
-+#endif
-+ .explicit_stop = 1,
-+};
-+
-+static struct i2c_algorithm i2c_dw_algo = {
-+ .master_xfer = i2c_dw_xfer,
-+ .functionality = i2c_dw_func,
-+};
-+
-+/**
-+ * i2c_dw_get_clk_rate_khz
-+ * @param dev: Pointer to I2C device private data
-+ * @return clock rate in kHz
-+ *
-+ * Ancillary function returning the frequency of the clock supplied to the
-+ * interface.
-+ */
-+static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
-+{
-+ return dev->controller->clk_khz;
-+}
-+
-+/**
-+ * intel_cln_i2c_probe
-+ * @param pdev: Pointer to GIP PCI device
-+ * @param drvdata: private driver data
-+ * @return 0 success < 0 failure
-+ *
-+ * Perform I2C-specific probing on behalf of the top-level GIP driver.
-+ * Also call into I2C core driver routines for initiating the device.
-+ */
-+int intel_cln_i2c_probe(struct pci_dev *pdev,
-+ struct dw_i2c_dev **drvdata,
-+ struct intel_cln_gip_pdata *pdata)
-+{
-+ int retval = 0;
-+ resource_size_t start = 0, len = 0;
-+ struct dw_i2c_dev *dev = NULL;
-+ struct i2c_adapter *adap = NULL;
-+ void __iomem *reg_base = NULL;
-+ struct dw_pci_controller *controller = NULL;
-+ int std_mode = -1;
-+
-+ controller = &cln_gip_i2c_controller;
-+
-+ /* Clanton default configuration is fast mode, unless otherwise forced */
-+ if (-1 != i2c_std_mode) {
-+ switch (i2c_std_mode) {
-+ case 0:
-+ case 1:
-+ std_mode = i2c_std_mode;
-+ break;
-+ default:
-+ dev_err(&pdev->dev, "invalid i2c_std_mode param val %d."
-+ " Using driver default\n", i2c_std_mode);
-+ break;
-+ }
-+ } else if (pdata) {
-+ switch (pdata->i2c_std_mode) {
-+ case 0:
-+ case 1:
-+ std_mode = pdata->i2c_std_mode;
-+ break;
-+ default:
-+ dev_err(&pdev->dev, "invalid i2c_std_mode pdata val %d."
-+ " Usign driver default\n", pdata->i2c_std_mode);
-+ break;
-+ }
-+ }
-+ if (-1 != std_mode) {
-+ if (0 == std_mode) {
-+ controller->bus_cfg |= DW_IC_CON_SPEED_FAST;
-+ controller->bus_cfg &= ~DW_IC_CON_SPEED_STD;
-+ } else {
-+ controller->bus_cfg &= ~DW_IC_CON_SPEED_FAST;
-+ controller->bus_cfg |= DW_IC_CON_SPEED_STD;
-+ }
-+ dev_info(&pdev->dev, "i2c speed set to %skHz\n",
-+ std_mode ? "100" : "400");
-+ }
-+
-+ /* Determine the address of the I2C area */
-+ start = pci_resource_start(pdev, GIP_I2C_BAR);
-+ len = pci_resource_len(pdev, GIP_I2C_BAR);
-+ if (!start || len == 0) {
-+ dev_err(&pdev->dev, "bar%d not set\n", GIP_I2C_BAR);
-+ retval = -ENODEV;
-+ goto err;
-+ }
-+
-+ reg_base = ioremap_nocache(start, len);
-+ if (!reg_base) {
-+ dev_err(&pdev->dev, "I/O memory remapping failed\n");
-+ retval = -ENOMEM;
-+ goto err;
-+ }
-+
-+ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
-+ if (!dev) {
-+ retval = -ENOMEM;
-+ goto err_iounmap;
-+ }
-+
-+ init_completion(&dev->cmd_complete);
-+ mutex_init(&dev->lock);
-+ dev->clk = NULL;
-+ dev->controller = controller;
-+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
-+ dev->base = reg_base;
-+ dev->dev = get_device(&pdev->dev);
-+ dev->functionality =
-+ I2C_FUNC_I2C |
-+ I2C_FUNC_10BIT_ADDR |
-+ I2C_FUNC_SMBUS_BYTE |
-+ I2C_FUNC_SMBUS_BYTE_DATA |
-+ I2C_FUNC_SMBUS_WORD_DATA |
-+ I2C_FUNC_SMBUS_I2C_BLOCK;
-+ dev->master_cfg = controller->bus_cfg;
-+
-+ *drvdata = dev;
-+
-+ dev->tx_fifo_depth = controller->tx_fifo_depth;
-+ dev->rx_fifo_depth = controller->rx_fifo_depth;
-+ dev->explicit_stop = controller->explicit_stop;
-+ retval = i2c_dw_init(dev);
-+ if (retval)
-+ goto err_release_drvdata;
-+
-+ adap = &dev->adapter;
-+ i2c_set_adapdata(adap, dev);
-+ adap->owner = THIS_MODULE;
-+ adap->class = 0;
-+ adap->algo = &i2c_dw_algo;
-+ adap->dev.parent = &pdev->dev;
-+ adap->nr = controller->bus_num;
-+ snprintf(adap->name, sizeof(adap->name), "intel_cln_gip_i2c");
-+
-+ i2c_dw_disable_int(dev);
-+ i2c_dw_clear_int(dev);
-+ retval = i2c_add_numbered_adapter(adap);
-+ if (retval) {
-+ dev_err(&pdev->dev, "failure adding I2C adapter\n");
-+ goto err_release_drvdata;
-+ }
-+
-+ return 0;
-+
-+err_release_drvdata:
-+ put_device(&pdev->dev);
-+ kfree(dev);
-+err_iounmap:
-+ iounmap(reg_base);
-+err:
-+ return retval;
-+}
-+
-+/**
-+ * intel_cln_i2c_remove
-+ * @param pdev: Pointer to GIP PCI device
-+ * @param dev: Pointer to I2C private data
-+ *
-+ * Perform I2C-specific resource release on behalf of the top-level GIP driver.
-+ */
-+void intel_cln_i2c_remove(struct pci_dev *pdev,
-+ struct dw_i2c_dev *dev)
-+{
-+
-+ if (NULL == dev) {
-+ dev_err(&pdev->dev, "%s: failure getting driver data\n",
-+ __func__);
-+ return;
-+ }
-+
-+ i2c_dw_disable(dev);
-+ i2c_del_adapter(&dev->adapter);
-+ iounmap(dev->base);
-+
-+ kfree(dev);
-+}
-diff --git a/drivers/mfd/intel_cln_gip_pdata.c b/drivers/mfd/intel_cln_gip_pdata.c
-new file mode 100644
-index 0000000..853efdd
---- /dev/null
-+++ b/drivers/mfd/intel_cln_gip_pdata.c
-@@ -0,0 +1,25 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/mfd/intel_cln_gip_pdata.h>
-+
-+struct intel_cln_gip_pdata *(*intel_cln_gip_get_pdata)(void) = NULL;
-+EXPORT_SYMBOL_GPL(intel_cln_gip_get_pdata);
-diff --git a/drivers/mfd/intel_cln_gip_test.c b/drivers/mfd/intel_cln_gip_test.c
-new file mode 100644
-index 0000000..c88f95c
---- /dev/null
-+++ b/drivers/mfd/intel_cln_gip_test.c
-@@ -0,0 +1,1131 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton GIP (GPIO/I2C) Test module
-+ *
-+ * Clanton GIP + North-Cluster GPIO test module.
-+ */
-+
-+#include <asm/tsc.h>
-+#include <linux/cdev.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/fs.h>
-+#include <linux/gpio.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/slab.h>
-+#include <linux/workqueue.h>
-+
-+#define DRIVER_NAME "intel_cln_gip_test"
-+
-+/**************************** Exported to LISA *******************************/
-+
-+/*
-+ * Internally-used ioctl code. At the moment it is not reserved by any mainline
-+ * driver.
-+ */
-+#define GIP_TEST_IOCTL_CODE 0xE0
-+
-+/*
-+ * Integers for ioctl operation.
-+ */
-+#define IOCTL_CLN_GPIO_11 _IO(GIP_TEST_IOCTL_CODE, 0x00)
-+#define IOCTL_CLN_GPIO_11_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x01)
-+#define IOCTL_CLN_GPIO_12 _IO(GIP_TEST_IOCTL_CODE, 0x02)
-+#define IOCTL_CLN_GPIO_12_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x03)
-+#define IOCTL_CLN_GPIO_13 _IO(GIP_TEST_IOCTL_CODE, 0x04)
-+#define IOCTL_CLN_GPIO_13_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x05)
-+#define IOCTL_CLN_GPIO_14 _IO(GIP_TEST_IOCTL_CODE, 0x06)
-+#define IOCTL_CLN_GPIO_14_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x07)
-+#define IOCTL_CLN_GPIO_15 _IO(GIP_TEST_IOCTL_CODE, 0x08)
-+#define IOCTL_CLN_GPIO_15_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x09)
-+#define IOCTL_CLN_GPIO_16 _IO(GIP_TEST_IOCTL_CODE, 0x0A)
-+#define IOCTL_CLN_GPIO_16_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0B)
-+#define IOCTL_CLN_GPIO_17 _IO(GIP_TEST_IOCTL_CODE, 0x0C)
-+#define IOCTL_CLN_GPIO_17_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0D)
-+#define IOCTL_CLN_GPIO_19 _IO(GIP_TEST_IOCTL_CODE, 0x0E)
-+#define IOCTL_CLN_GPIO_19_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0F)
-+#define IOCTL_CLN_GPIO_20 _IO(GIP_TEST_IOCTL_CODE, 0x10)
-+#define IOCTL_CLN_GPIO_20_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x11)
-+#define IOCTL_CLN_GPIO_21 _IO(GIP_TEST_IOCTL_CODE, 0x12)
-+#define IOCTL_CLN_GPIO_21_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x13)
-+#define IOCTL_CLN_GPIO_24 _IO(GIP_TEST_IOCTL_CODE, 0x14)
-+#define IOCTL_CLN_GPIO_26 _IO(GIP_TEST_IOCTL_CODE, 0x15)
-+#define IOCTL_CLN_GPIO_26_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x16)
-+/* Exercise callbacks for S0/S3 power-state transitions and vice-versa */
-+#define IOCTL_CLN_GIP_SYSTEM_SUSPEND _IO(GIP_TEST_IOCTL_CODE, 0x17)
-+#define IOCTL_CLN_GIP_SYSTEM_RESUME _IO(GIP_TEST_IOCTL_CODE, 0x18)
-+#define IOCTL_CLN_GPIO_NMI_ENABLE _IO(GIP_TEST_IOCTL_CODE, 0x19)
-+#define IOCTL_CLN_GPIO_NMI_DISABLE _IO(GIP_TEST_IOCTL_CODE, 0x1A)
-+
-+#define GPIO_INT_EDGE_POS_LABEL "gpio-edge-pos"
-+#define GPIO_INT_EDGE_NEG_LABEL "gpio-edge-neg"
-+#define GPIO_INT_LEVEL_HIGH_LABEL "gpio-level-hi"
-+#define GPIO_INT_LEVEL_LOW_LABEL "gpio-level-lo"
-+#define GPIO_INT_BASIC_LABEL "gpio-edge-pos-basic"
-+#define GPIO_PM_TEST_IRQ_LABEL "gpio_pm_test_irq"
-+
-+/*
-+ * Board GPIO numbers.
-+ * Mapping between the North/South cluster GPIO and GPIOLIB IDs.
-+ */
-+#define SUT_GPIO_NC_0 0x00
-+#define SUT_GPIO_NC_1 0x01
-+#define SUT_GPIO_NC_2 0x02
-+#define SUT_GPIO_NC_7 0x07
-+#define SUT_GPIO_SC_0 0x08
-+#define SUT_GPIO_SC_1 0x09
-+#define SUT_GPIO_SC_6 0x0E
-+#define SUT_GPIO_SC_7 0x0F
-+
-+/*
-+ * Bitbanged SPI bus numbers.
-+ */
-+#define GPIO_NC_BITBANG_SPI_BUS 0x0
-+#define GPIO_SC_BITBANG_SPI_BUS 0x1
-+
-+/*****************************************************************************/
-+
-+/**
-+ * struct intel_cln_gip_dev
-+ *
-+ * Structure to represent module state/data/etc
-+ */
-+struct intel_cln_gip_test_dev {
-+ unsigned int opened;
-+ struct platform_device *pldev; /* Platform device */
-+ struct cdev cdev;
-+ struct mutex open_lock;
-+};
-+
-+static struct intel_cln_gip_test_dev gip_test_dev;
-+static struct class *gip_test_class;
-+static DEFINE_MUTEX(gip_test_mutex);
-+static int gip_test_major;
-+
-+/*
-+ * Level-triggered interrupt variables
-+ */
-+/* Level-triggered GPIO workqueue */
-+static struct delayed_work work;
-+/* Level-triggered interrupt counter */
-+static unsigned int level_int_count;
-+/* By default, a level-triggered interrupt is a low-level triggered */
-+static int level_high_triggered = 0;
-+
-+/*
-+ * Interrupt performance metrics variables and parameters
-+ */
-+/* How many captures */
-+#define INT_PERF_TEST_CAPTURES 10000
-+/* Timestamp for latency test interrupt handler */
-+static cycles_t perf_t1;
-+/* Captures to be returned to user space */
-+static cycles_t deltas[INT_PERF_TEST_CAPTURES];
-+/* Couldn't find the actual define for this */
-+#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
-+
-+static irqreturn_t gpio_pm_test_handler(int irq, void *dev_id)
-+{
-+ /* Do nothing, just acknowledge the IRQ subsystem */
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t gpio_latency_handler(int irq, void *dev_id)
-+{
-+ /* t0 */
-+ perf_t1 = get_cycles();
-+
-+ gpio_set_value(SUT_GPIO_SC_0, 0);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t gpio_basic_handler(int irq, void *dev_id)
-+{
-+ /* Do nothing, just acknowledge the IRQ subsystem */
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t gpio_pos_edge_handler(int irq, void *dev_id)
-+{
-+ /* Do nothing, just acknowledge the IRQ subsystem */
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t gpio_neg_edge_handler(int irq, void *dev_id)
-+{
-+ /* Do nothing, just acknowledge the IRQ subsystem */
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t gpio_level_handler(int irq, void *dev_id)
-+{
-+ /* Untrigger the interrupt */
-+ gpio_set_value(SUT_GPIO_SC_7, level_high_triggered ? 0 : 1);
-+
-+ level_int_count ++;
-+ if (level_int_count < 1000) {
-+ /* Next task due in a jiffy */
-+ schedule_delayed_work(&work, 1);
-+ } else if (level_int_count == 1000){
-+ /* OK */
-+ } else {
-+ /*
-+ * We may get spurious interrupts. This because the TE requires
-+ * some time to drive the actual value to the GPIO.
-+ */
-+ pr_info("Spurious interrupt\n");
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static void gpio_level_drive(struct work_struct *work)
-+{
-+ /* TE to trigger the interrupt */
-+ gpio_set_value(SUT_GPIO_SC_7, level_high_triggered ? 1 : 0);
-+}
-+
-+/**
-+ * gpio_sc_level_int
-+ *
-+ * Request level triggered IRQ for SUT_GPIO_SC_6 and register
-+ * SUT_GPIO_SC_7 as output GPIO.
-+ * If positive equals to 0, the IRQ is high-level triggered.
-+ * Otherwise, low-level triggered.
-+ * Mask the IRQ if requested.
-+ */
-+static int gpio_sc_level_int(int positive, int masking)
-+{
-+ int ret = 0;
-+ int irq = -1;
-+
-+ unsigned long out_init_val =
-+ (positive ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
-+
-+ level_high_triggered = positive;
-+
-+ /* Initialise workqueue task */
-+ INIT_DELAYED_WORK(&work, gpio_level_drive);
-+
-+ if (!gpio_is_valid(SUT_GPIO_SC_6)) {
-+ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_6);
-+ ret = -1;
-+ goto fail;
-+ }
-+ if (!gpio_is_valid(SUT_GPIO_SC_7)) {
-+ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_7);
-+ ret = -1;
-+ goto fail;
-+ }
-+
-+ ret = gpio_request_one(SUT_GPIO_SC_6, GPIOF_IN, "gpio_hi_level");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_6, ret);
-+ goto fail;
-+ }
-+ ret = gpio_request_one(SUT_GPIO_SC_7, out_init_val, "gpio_output");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_7, ret);
-+ goto fail_release_first_gpio;
-+ }
-+
-+ irq = gpio_to_irq(SUT_GPIO_SC_6);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
-+ goto fail_release_second_gpio;
-+ }
-+
-+ if (0 != (ret = request_irq(irq, gpio_level_handler,
-+ positive ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW,
-+ positive ? GPIO_INT_LEVEL_HIGH_LABEL : GPIO_INT_LEVEL_LOW_LABEL,
-+ NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_6);
-+ goto fail_release_second_gpio;
-+ }
-+
-+ level_int_count = 0;
-+
-+ pr_info("Registered output gpio%d and IRQ for gpio%d\n", SUT_GPIO_SC_7,
-+ SUT_GPIO_SC_6);
-+
-+ if (masking) {
-+ disable_irq(gpio_to_irq(SUT_GPIO_SC_6));
-+ pr_info("Masked gpio%d IRQ\n", SUT_GPIO_SC_6);
-+ }
-+
-+ /*
-+ * Submit task to workqueue to drive the external Test Equipment.
-+ * Note the task is delayed long enough to have Aarvark already set up.
-+ * This because Aardvark has to ignore the initial glitches during the
-+ * previous GPIO setup phase.
-+ */
-+ schedule_delayed_work(&work, 20 * HZ);
-+
-+ return 0;
-+
-+fail_release_second_gpio:
-+ gpio_free(SUT_GPIO_SC_7);
-+fail_release_first_gpio:
-+ gpio_free(SUT_GPIO_SC_6);
-+fail:
-+ pr_err("%s() failed\n", __func__);
-+
-+ return ret;
-+}
-+
-+/**
-+ * gpio_sc_level_int_teardown
-+ *
-+ * Release resources reserved by gpio_sc_level_int().
-+ */
-+static int gpio_sc_level_int_teardown(void)
-+{
-+ int irq = -1;
-+
-+ if (0 != cancel_delayed_work_sync(&work))
-+ pr_warn("delayed work was still pending\n");
-+
-+ irq = gpio_to_irq(SUT_GPIO_SC_6);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
-+ } else {
-+ free_irq(irq, NULL);
-+ }
-+
-+ /* Make sure no handler is still running by this time */
-+ mdelay(20);
-+
-+ gpio_free(SUT_GPIO_SC_7);
-+ gpio_free(SUT_GPIO_SC_6);
-+
-+ return 0;
-+}
-+
-+/*
-+ * gpio_sc_interrupt_perf
-+ *
-+ * Performs a basic GPIO interrupt latency test by timestamping delta between
-+ * interrupt driven and handled over a GPIO loopback.
-+ *
-+ * Returns to userspace the array of deltas obtained during each capture.
-+ * A total amount of INT_PERF_TEST_CAPTURES captures is performed.
-+ *
-+ */
-+static int gpio_sc_interrupt_perf(unsigned long user_memloc)
-+{
-+ int ret = 0;
-+ int irq = -1;
-+ int gpio_input = SUT_GPIO_SC_1;
-+ int gpio_output = SUT_GPIO_SC_0;
-+ unsigned int i = 0;
-+ cycles_t perf_t0 = 0;
-+ cycles_t delta = 0;
-+
-+ /* Casting pointer to user-space location to write */
-+ cycles_t __user *user_ptr = (cycles_t __user *)user_memloc;
-+
-+ /* Can we copy the captures array into user-space location? */
-+ if (!access_ok(VERIFY_WRITE, user_ptr, sizeof(deltas))) {
-+ pr_err("can't copy 0x%x bytes to user-space address 0x%p\n",
-+ sizeof(deltas),user_ptr);
-+ return -EFAULT;
-+ }
-+
-+ /* Setup the GPIO */
-+ if (!gpio_is_valid(gpio_input)) {
-+ pr_err("gpio%d is invalid\n", gpio_input);
-+ ret = -1;
-+ goto fail;
-+ }
-+ if (!gpio_is_valid(gpio_output)) {
-+ pr_err("gpio%d is invalid\n", gpio_output);
-+ ret = -1;
-+ goto fail;
-+ }
-+ ret = gpio_request_one(gpio_input, GPIOF_IN, "gpio_intperf_in");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", gpio_input, ret);
-+ goto fail;
-+ }
-+ ret = gpio_request_one(gpio_output, GPIOF_OUT_INIT_LOW, "gpio_intperf_out");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", gpio_output, ret);
-+ goto fail_release_input_gpio;
-+ }
-+
-+ /* Setup IRQ handler for input GPIO */
-+ irq = gpio_to_irq(gpio_input);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", gpio_input);
-+ goto fail_release_output_gpio;
-+ }
-+ if (0 != (ret = request_irq(irq, gpio_latency_handler,
-+ IRQF_TRIGGER_RISING, "gpio_latency_handler", NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", gpio_input);
-+ goto fail_release_output_gpio;
-+ }
-+
-+ /* Perform test */
-+ for (i = 0; i < INT_PERF_TEST_CAPTURES; i ++) {
-+ /* t0 */
-+ perf_t0 = get_cycles();
-+
-+ /* Trigger interrupt */
-+ gpio_set_value(gpio_output, 1);
-+ mdelay(2);
-+
-+ /* Check for wrap-around and store delta */
-+ if(perf_t0 < perf_t1) {
-+ delta = perf_t1 - perf_t0;
-+ } else {
-+ delta = perf_t1 + (UINT64_MAX - perf_t0);
-+ }
-+ deltas[i] = delta;
-+ }
-+
-+ /* Expose results to userspace */
-+ ret = copy_to_user(user_ptr, &deltas, sizeof(deltas));
-+
-+ /* Release resources */
-+
-+ free_irq(irq, NULL);
-+
-+fail_release_output_gpio:
-+ gpio_free(gpio_output);
-+fail_release_input_gpio:
-+ gpio_free(gpio_input);
-+fail:
-+ if (0 != ret) {
-+ pr_err("%s() failed\n", __func__);
-+ }
-+
-+ return ret;
-+}
-+
-+/**
-+ * gpio_sc_pm_test_int
-+ *
-+ * Request rising edge-triggered IRQ for SUT_GPIO_SC_0
-+ */
-+static int gpio_sc_pm_test_int(void)
-+{
-+ int ret = 0;
-+ int irq = -1;
-+ int gpio_input = SUT_GPIO_SC_0;
-+
-+ /* Setup the GPIO */
-+ if (!gpio_is_valid(gpio_input)) {
-+ pr_err("gpio%d is invalid\n", gpio_input);
-+ ret = -1;
-+ goto fail;
-+ }
-+ ret = gpio_request_one(gpio_input, GPIOF_IN, "gpio_pm_test_in");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", gpio_input, ret);
-+ goto fail;
-+ }
-+
-+ /* Setup IRQ handler for input GPIO */
-+ irq = gpio_to_irq(gpio_input);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", gpio_input);
-+ goto fail_release_input_gpio;
-+ }
-+ if (0 != (ret = request_irq(irq, gpio_pm_test_handler,
-+ IRQF_TRIGGER_RISING, GPIO_PM_TEST_IRQ_LABEL, NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", gpio_input);
-+ goto fail_release_input_gpio;
-+ }
-+
-+ return 0;
-+
-+fail_release_input_gpio:
-+ gpio_free(gpio_input);
-+fail:
-+ return ret;
-+}
-+
-+/**
-+ * gpio_sc_pm_test_int
-+ *
-+ * Release resources reserved by gpio_sc_edge_int()
-+ */
-+static int gpio_sc_pm_test_int_teardown(void)
-+{
-+ int irq = -1;
-+
-+ irq = gpio_to_irq(SUT_GPIO_SC_0);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_0);
-+ } else {
-+ free_irq(irq, NULL);
-+ }
-+
-+ gpio_free(SUT_GPIO_SC_0);
-+
-+ return 0;
-+}
-+
-+/**
-+ * gpio_sc_edge_int
-+ *
-+ * Request IRQ for SUT_GPIO_SC_6 and SUT_GPIO_SC_7, respectively positive-edge
-+ * and negative edge-triggered.
-+ * Mask the IRQs if requested.
-+ */
-+static int gpio_sc_edge_int(int masking)
-+{
-+ int ret = 0;
-+ int irq_pos = -1, irq_neg = -1;
-+
-+ if (!gpio_is_valid(SUT_GPIO_SC_6)) {
-+ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_6);
-+ ret = -1;
-+ goto fail;
-+ }
-+ if (!gpio_is_valid(SUT_GPIO_SC_7)) {
-+ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_7);
-+ ret = -1;
-+ goto fail;
-+ }
-+
-+ ret = gpio_request_one(SUT_GPIO_SC_6, GPIOF_IN, "gpio_pos_edge");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_6, ret);
-+ goto fail;
-+ }
-+ ret = gpio_request_one(SUT_GPIO_SC_7, GPIOF_IN, "gpio_neg_edge");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_7, ret);
-+ goto fail_release_first_gpio;
-+ }
-+
-+ irq_pos = gpio_to_irq(SUT_GPIO_SC_6);
-+ if (irq_pos < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
-+ goto fail_release_second_gpio;
-+ }
-+ irq_neg = gpio_to_irq(SUT_GPIO_SC_7);
-+ if (irq_neg < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_7);
-+ goto fail_release_second_gpio;
-+ }
-+
-+ if (0 != (ret = request_irq(irq_pos, gpio_pos_edge_handler,
-+ IRQF_TRIGGER_RISING, GPIO_INT_EDGE_POS_LABEL, NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_6);
-+ goto fail_release_second_gpio;
-+ }
-+ if (0 != (ret = request_irq(irq_neg, gpio_neg_edge_handler,
-+ IRQF_TRIGGER_FALLING, GPIO_INT_EDGE_NEG_LABEL, NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_7);
-+ goto fail_release_first_gpio_irq;
-+ }
-+
-+ pr_info("Registered gpio%d and gpio%d IRQs\n", SUT_GPIO_SC_6,
-+ SUT_GPIO_SC_7);
-+
-+ if (masking) {
-+ disable_irq(gpio_to_irq(SUT_GPIO_SC_6));
-+ disable_irq(gpio_to_irq(SUT_GPIO_SC_7));
-+ pr_info("Masked gpio%d and gpio%d IRQs\n", SUT_GPIO_SC_6,
-+ SUT_GPIO_SC_7);
-+ }
-+
-+ return 0;
-+
-+fail_release_first_gpio_irq:
-+ free_irq(irq_pos, NULL);
-+fail_release_second_gpio:
-+ gpio_free(SUT_GPIO_SC_7);
-+fail_release_first_gpio:
-+ gpio_free(SUT_GPIO_SC_6);
-+fail:
-+ pr_err("%s() failed\n", __func__);
-+
-+ return ret;
-+}
-+
-+/**
-+ * gpio_sc_edge_int_teardown
-+ *
-+ * Release resources reserved by gpio_sc_edge_int()
-+ */
-+static int gpio_sc_edge_int_teardown(void)
-+{
-+ int irq_pos = -1, irq_neg = -1;
-+
-+ irq_neg = gpio_to_irq(SUT_GPIO_SC_7);
-+ if (irq_neg < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_7);
-+ } else {
-+ free_irq(irq_neg, NULL);
-+ }
-+ irq_pos = gpio_to_irq(SUT_GPIO_SC_6);
-+ if (irq_pos < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
-+ } else {
-+ free_irq(irq_pos, NULL);
-+ }
-+
-+ gpio_free(SUT_GPIO_SC_7);
-+ gpio_free(SUT_GPIO_SC_6);
-+
-+ return 0;
-+}
-+
-+/**
-+ * gpio_sc_basic_int
-+ *
-+ * Register rising-edge interrupt handler on SUT_GPIO_SC_1
-+ */
-+static int gpio_sc_basic_int(void)
-+{
-+ int ret = 0;
-+ int irq = -1;
-+ unsigned int gpio = SUT_GPIO_SC_1;
-+
-+ if (!gpio_is_valid(gpio)) {
-+ pr_err("gpio%d is invalid\n", gpio);
-+ ret = -1;
-+ goto fail;
-+ }
-+
-+ ret = gpio_request_one(gpio, GPIOF_IN, "gpio_pos_edge_basic");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", gpio, ret);
-+ goto fail;
-+ }
-+
-+ irq = gpio_to_irq(gpio);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", gpio);
-+ goto fail_release_gpio;
-+ }
-+
-+ if (0 != (ret = request_irq(irq, gpio_basic_handler,
-+ IRQF_TRIGGER_RISING, GPIO_INT_BASIC_LABEL, NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", gpio);
-+ goto fail_release_gpio;
-+ }
-+
-+ pr_info("Registered gpio%d IRQ\n", gpio);
-+
-+ return 0;
-+
-+fail_release_gpio:
-+ gpio_free(gpio);
-+fail:
-+ pr_err("%s() failed\n", __func__);
-+
-+ return ret;
-+}
-+
-+/**
-+ * gpio_sc_basic_int_teardown
-+ *
-+ * Release resources reserved by gpio_sc_basic_int()
-+ */
-+static int gpio_sc_basic_int_teardown(void)
-+{
-+ int irq = -1;
-+ unsigned int gpio = SUT_GPIO_SC_1;
-+
-+ irq = gpio_to_irq(gpio);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", gpio);
-+ } else {
-+ free_irq(irq, NULL);
-+ }
-+
-+ gpio_free(gpio);
-+
-+ return 0;
-+}
-+
-+/**
-+ * gpio_spidev_register
-+ *
-+ * Register a bitbanged SPI platform device and export a `spidev' to userspace.
-+ * For North Cluster and South Cluster.
-+ */
-+static int gpio_spidev_register(int north_cluster)
-+{
-+ /* Not needed anymore */
-+ return 0;
-+}
-+
-+/**
-+ * gpio_spidev_unregister
-+ *
-+ * Release a bitbanged SPI platform device and its `spidev' interface.
-+ * For North Cluster and South Cluster.
-+ */
-+static int gpio_spidev_unregister(int north_cluster)
-+{
-+ /* Not needed anymore */
-+ return 0;
-+}
-+
-+/**
-+ * gip_system_power_transition
-+ *
-+ * @param state: 0 if transition to S3, !0 if transition to S0
-+ * @return 0 success < 0 failure
-+ *
-+ * Exercise system-wide suspend/resume power management transitions.
-+ *
-+ */
-+static int gip_system_power_transition(int state)
-+{
-+ struct pci_dev *gip = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0934, NULL);
-+ if (NULL == gip) {
-+ pr_err("can't find GIP PCI device\n");
-+ return -ENOENT;
-+ }
-+
-+ if (0 == state) {
-+ gip->driver->driver.pm->suspend(&gip->dev);
-+ } else {
-+ gip->driver->driver.pm->resume(&gip->dev);
-+ }
-+
-+ /* Decrement reference count of PCI device */
-+ if (NULL != pci_get_device(PCI_VENDOR_ID_INTEL, 0x0934, gip)) {
-+ pr_warn("found duplicate of GIP PCI device?!\n");
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * gpio_nmi_enable
-+ *
-+ * @param enable: 0 to disable, !0 to enable
-+ * @return 0 success < 0 failure
-+ *
-+ * Hack the legacy GPIO hardware to enable rising-edge triggered NMI on Core
-+ * Well gpio0.
-+ *
-+ */
-+static int gpio_nmi_enable(int enable)
-+{
-+ unsigned int base_u32 = 0x0;
-+ unsigned short base = 0x0;
-+ struct pci_dev *ilb = pci_get_device(PCI_VENDOR_ID_INTEL,
-+ PCI_DEVICE_ID_INTEL_CLANTON_ILB,
-+ NULL);
-+ /* Assume interrupts are disabled by default by BIOS */
-+ unsigned char gpio = enable ? 0x01 : 0x00;
-+
-+ if (NULL == ilb) {
-+ pr_err("can't find iLB device\n");
-+ return -ENOENT;
-+ }
-+
-+ /* The GPIO base address is @ offset 0x44. Sussed out from driver */
-+ pci_read_config_dword(ilb, 0x44, &base_u32);
-+ if (0x0 == base_u32) {
-+ pr_err("can't read iLB GPIO baseaddr\n");
-+ return -ENOENT;
-+ }
-+ base = (unsigned short)base_u32;
-+
-+ /*
-+ * Prepare for rising edge NMI triggering. This assumes the pin
-+ * is already set as input.
-+ */
-+#define CGTPE 0x0C /* Core Well trigger positive edge */
-+#define CGTS 0x1C /* Core Well trigges status - W1C */
-+#define CGNMIEN 0x40 /* Core Well NMI enable */
-+ outb(0x01, base + CGTS);
-+ outb(gpio, base + CGTPE);
-+ outb(gpio, base + CGNMIEN);
-+#undef CGTPE
-+#undef CGTS
-+#undef CGNMIEN
-+
-+ return 0;
-+}
-+
-+/**
-+ * gpio_sc_debounce
-+ *
-+ * Enable GPIO debounce functionality for SC_GPIO_1 (edge and level triggered)
-+ *
-+ */
-+static int gpio_sc_debounce(int level)
-+{
-+ int ret = 0;
-+ int irq = -1;
-+ int gpio = SUT_GPIO_SC_0;
-+
-+ if (!gpio_is_valid(gpio)) {
-+ pr_err("gpio%d is invalid\n", gpio);
-+ ret = -1;
-+ goto fail;
-+ }
-+
-+ ret = gpio_request_one(gpio, GPIOF_IN,
-+ level ? "gpio_level_mask" : "gpio_edge_mask");
-+ if (ret) {
-+ pr_err("can't request gpio%d (error %d)\n", gpio, ret);
-+ goto fail;
-+ }
-+
-+ irq = gpio_to_irq(gpio);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", gpio);
-+ goto fail_release_gpio;
-+ }
-+
-+ /*
-+ * Register IRQ. gpio_pos_edge_handler will do for both level and edge
-+ * interrupts, as it's nooping.
-+ */
-+ if (0 != (ret = request_irq(irq, gpio_pos_edge_handler,
-+ level ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_RISING,
-+ level ? GPIO_INT_LEVEL_HIGH_LABEL : GPIO_INT_EDGE_POS_LABEL,
-+ NULL))) {
-+ pr_err("can't request IRQ for gpio%d\n", gpio);
-+ goto fail_release_gpio;
-+ }
-+
-+ /* Set debounce */
-+ if (0 != (ret = gpio_set_debounce(gpio, 1))) {
-+ pr_err("can't set debounce for gpio%d\n", gpio);
-+ goto fail_free_irq;
-+ }
-+
-+ return 0;
-+
-+fail_free_irq:
-+ free_irq(irq, NULL);
-+fail_release_gpio:
-+ gpio_free(gpio);
-+fail:
-+ pr_err("%s() failed\n", __func__);
-+
-+ return ret;
-+}
-+
-+/**
-+ * gpio_sc_debounce_teardown
-+ *
-+ * Undo gpio_sc_debounce
-+ *
-+ */
-+static int gpio_sc_debounce_teardown(int level)
-+{
-+ int irq = -1;
-+ unsigned int gpio = SUT_GPIO_SC_0;
-+
-+ irq = gpio_to_irq(gpio);
-+ if (irq < 0) {
-+ pr_err("can't map gpio%d to IRQ\n", gpio);
-+ } else {
-+ free_irq(irq, NULL);
-+ }
-+
-+ gpio_free(gpio);
-+
-+ return 0;
-+}
-+
-+/*
-+ * File ops
-+ */
-+static long gip_test_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ int ret = -EINVAL;
-+
-+ switch (cmd) {
-+ case IOCTL_CLN_GPIO_11:
-+ /* Edge-triggered interrupts */
-+ ret = gpio_sc_edge_int(0);
-+ break;
-+ case IOCTL_CLN_GPIO_11_CLEANUP:
-+ /* Edge-triggered interrupts cleanup */
-+ ret = gpio_sc_edge_int_teardown();
-+ break;
-+ case IOCTL_CLN_GPIO_12:
-+ /* Edge-triggered interrupts (masking) */
-+ ret = gpio_sc_edge_int(1);
-+ break;
-+ case IOCTL_CLN_GPIO_12_CLEANUP:
-+ /* Edge-triggered interrupts (masking) cleanup */
-+ ret = gpio_sc_edge_int_teardown();
-+ break;
-+ case IOCTL_CLN_GPIO_13:
-+ /* GPIO debounce (edge) */
-+ ret = gpio_sc_debounce(0);
-+ break;
-+ case IOCTL_CLN_GPIO_13_CLEANUP:
-+ /* GPIO debounce cleanup (edge) */
-+ ret = gpio_sc_debounce_teardown(0);
-+ break;
-+ case IOCTL_CLN_GPIO_14:
-+ /* High-level triggered interrupts */
-+ ret = gpio_sc_level_int(1, 0);
-+ break;
-+ case IOCTL_CLN_GPIO_14_CLEANUP:
-+ /* High-level triggered interrupts cleanup */
-+ ret = gpio_sc_level_int_teardown();
-+ break;
-+ case IOCTL_CLN_GPIO_15:
-+ /* Low-level triggered interrupts */
-+ ret = gpio_sc_level_int(0, 0);
-+ break;
-+ case IOCTL_CLN_GPIO_15_CLEANUP:
-+ /*Low-level triggered interrupts cleanup */
-+ ret = gpio_sc_level_int_teardown();
-+ break;
-+ case IOCTL_CLN_GPIO_16:
-+ /* Level triggered interrupts (masking) */
-+ ret = gpio_sc_level_int(1, 1);
-+ break;
-+ case IOCTL_CLN_GPIO_16_CLEANUP:
-+ /* Level triggered interrupts (masking) cleanup */
-+ ret = gpio_sc_level_int_teardown();
-+ break;
-+ case IOCTL_CLN_GPIO_17:
-+ /* GPIO debounce (level) */
-+ ret = gpio_sc_debounce(1);
-+ break;
-+ case IOCTL_CLN_GPIO_17_CLEANUP:
-+ /* GPIO debounce cleanup (level) */
-+ ret = gpio_sc_debounce_teardown(1);
-+ break;
-+ case IOCTL_CLN_GPIO_19:
-+ /* Register IRQ for SC_GPIO0 (PM transitions test) */
-+ ret = gpio_sc_pm_test_int();
-+ break;
-+ case IOCTL_CLN_GPIO_19_CLEANUP:
-+ /* Free IRQ for SC_GPIO0 (PM transitions test) */
-+ ret = gpio_sc_pm_test_int_teardown();
-+ break;
-+ case IOCTL_CLN_GPIO_20:
-+ /* NC bitbanged SPI */
-+ ret = gpio_spidev_register(1);
-+ break;
-+ case IOCTL_CLN_GPIO_20_CLEANUP:
-+ /* NC bitbanged SPI cleanup */
-+ ret = gpio_spidev_unregister(1);
-+ break;
-+ case IOCTL_CLN_GPIO_21:
-+ /* SC bitbanged SPI */
-+ ret = gpio_spidev_register(0);
-+ break;
-+ case IOCTL_CLN_GPIO_21_CLEANUP:
-+ /* SC bitbanged SPI cleanup */
-+ ret = gpio_spidev_unregister(0);
-+ break;
-+ case IOCTL_CLN_GPIO_24:
-+ /*
-+ * SC GPIO interrupt performance test.
-+ * Note it's shared between CLN_GPIO_24 and CLN_GPIO_25
-+ * plus it doesn't need any cleanup call.
-+ */
-+ ret = gpio_sc_interrupt_perf(arg);
-+ break;
-+ case IOCTL_CLN_GPIO_26:
-+ /* Interrupt for basic loopback test */
-+ ret = gpio_sc_basic_int();
-+ break;
-+ case IOCTL_CLN_GPIO_26_CLEANUP:
-+ /* Interrupt for basic loopback test cleanup */
-+ ret = gpio_sc_basic_int_teardown();
-+ break;
-+ case IOCTL_CLN_GIP_SYSTEM_SUSPEND:
-+ ret = gip_system_power_transition(0);
-+ break;
-+ case IOCTL_CLN_GIP_SYSTEM_RESUME:
-+ ret = gip_system_power_transition(1);
-+ break;
-+ case IOCTL_CLN_GPIO_NMI_ENABLE:
-+ ret = gpio_nmi_enable(1);
-+ break;
-+ case IOCTL_CLN_GPIO_NMI_DISABLE:
-+ ret = gpio_nmi_enable(0);
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int gip_test_open(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&gip_test_mutex);
-+ nonseekable_open(inode, file);
-+
-+ if (mutex_lock_interruptible(&gip_test_dev.open_lock)) {
-+ mutex_unlock(&gip_test_mutex);
-+ return -ERESTARTSYS;
-+ }
-+
-+ if (gip_test_dev.opened) {
-+ mutex_unlock(&gip_test_dev.open_lock);
-+ mutex_unlock(&gip_test_mutex);
-+ return -EINVAL;
-+ }
-+
-+ gip_test_dev.opened++;
-+ mutex_unlock(&gip_test_dev.open_lock);
-+ mutex_unlock(&gip_test_mutex);
-+ return 0;
-+}
-+
-+static int gip_test_release(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&gip_test_dev.open_lock);
-+ gip_test_dev.opened = 0;
-+ mutex_unlock(&gip_test_dev.open_lock);
-+
-+ return 0;
-+}
-+
-+static const struct file_operations gip_test_file_ops = {
-+ .open = gip_test_open,
-+ .release = gip_test_release,
-+ .unlocked_ioctl = gip_test_ioctl,
-+ .llseek = no_llseek,
-+};
-+
-+/**
-+ * intel_cln_gip_test_probe
-+ *
-+ * @param pdev: Platform device
-+ * @return 0 success < 0 failure
-+ *
-+ * Callback from platform sub-system to probe
-+ */
-+static int intel_cln_gip_test_probe(struct platform_device * pdev)
-+{
-+ int retval = 0;
-+ unsigned int minor = 0;
-+
-+ mutex_init(&gip_test_dev.open_lock);
-+ cdev_init(&gip_test_dev.cdev, &gip_test_file_ops);
-+ gip_test_dev.cdev.owner = THIS_MODULE;
-+
-+ retval = cdev_add(&gip_test_dev.cdev, MKDEV(gip_test_major, minor), 1);
-+ if (retval) {
-+ printk(KERN_ERR "chardev registration failed\n");
-+ return -EINVAL;
-+ }
-+ if (IS_ERR(device_create(gip_test_class, NULL,
-+ MKDEV(gip_test_major, minor), NULL,
-+ "giptest%u", minor))){
-+ dev_err(&pdev->dev, "can't create device\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+
-+}
-+
-+static int intel_cln_gip_test_remove(struct platform_device * pdev)
-+{
-+ unsigned int minor = MINOR(gip_test_dev.cdev.dev);
-+
-+ device_destroy(gip_test_class, MKDEV(gip_test_major, minor));
-+ cdev_del(&gip_test_dev.cdev);
-+
-+ class_destroy(gip_test_class);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Platform structures useful for interface to PM subsystem
-+ */
-+static struct platform_driver intel_cln_gip_test_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .remove = intel_cln_gip_test_remove,
-+};
-+
-+/**
-+ * intel_cln_gip_test_init
-+ *
-+ * Load module.
-+ */
-+static int __init intel_cln_gip_test_init(void)
-+{
-+ int retval = 0;
-+ dev_t dev;
-+
-+ gip_test_class = class_create(THIS_MODULE,"cln_gip_test");
-+ if (IS_ERR(gip_test_class)) {
-+ retval = PTR_ERR(gip_test_class);
-+ printk(KERN_ERR "gip_test: can't register gip_test class\n");
-+ goto err;
-+ }
-+
-+ retval = alloc_chrdev_region(&dev, 0, 1, "gip_test");
-+ if (retval) {
-+ printk(KERN_ERR "earam_test: can't register character device\n");
-+ goto err_class;
-+ }
-+ gip_test_major = MAJOR(dev);
-+
-+ memset(&gip_test_dev, 0x00, sizeof(gip_test_dev));
-+ gip_test_dev.pldev = platform_create_bundle(
-+ &intel_cln_gip_test_driver, intel_cln_gip_test_probe, NULL, 0, NULL, 0);
-+
-+ if(IS_ERR(gip_test_dev.pldev)){
-+ printk(KERN_ERR "platform_create_bundle fail!\n");
-+ retval = PTR_ERR(gip_test_dev.pldev);
-+ goto err_class;
-+ }
-+
-+ return 0;
-+
-+err_class:
-+ class_destroy(gip_test_class);
-+err:
-+ return retval;
-+}
-+
-+static void __exit intel_cln_gip_test_exit(void)
-+{
-+ platform_device_unregister(gip_test_dev.pldev);
-+ platform_driver_unregister(&intel_cln_gip_test_driver);
-+}
-+
-+module_init(intel_cln_gip_test_init);
-+module_exit(intel_cln_gip_test_exit);
-+
-+MODULE_AUTHOR("Josef Ahmad <josef.ahmad@intel.com>");
-+MODULE_DESCRIPTION("Clanton GIP test module");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
-index 5624fcb..4fbb1fd 100644
---- a/drivers/mfd/lpc_sch.c
-+++ b/drivers/mfd/lpc_sch.c
-@@ -41,21 +41,41 @@
- #define WDTBASE 0x84
- #define WDT_IO_SIZE 64
-
-+/* BIOS control reg */
-+#define LPC_BIOS_CNTL 0xD8
-+#define LPC_BIOS_CNTL_WE 0x01
-+
-+/* Root complex base address derived registers */
-+#define RCBA_BASE 0xF0
-+
- static struct resource smbus_sch_resource = {
- .flags = IORESOURCE_IO,
- };
-
--
- static struct resource gpio_sch_resource = {
- .flags = IORESOURCE_IO,
- };
-
-+static struct resource spi_res = {
-+ .flags = IORESOURCE_MEM,
-+ .start = 0,
-+ .end = 0,
-+};
-+
-+static struct platform_device lpc_sch_spi = {
-+ .name = "spi-lpc-sch",
-+ .id = -1,
-+ .resource = &spi_res,
-+};
-+
- static struct mfd_cell lpc_sch_cells[] = {
-+#ifndef CONFIG_INTEL_QUARK_X1000_SOC
- {
- .name = "isch_smbus",
- .num_resources = 1,
- .resources = &smbus_sch_resource,
- },
-+#endif
- {
- .name = "sch_gpio",
- .num_resources = 1,
-@@ -79,6 +99,7 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CLANTON_ILB) },
- { 0, }
- };
- MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
-@@ -88,22 +109,26 @@ static int lpc_sch_probe(struct pci_dev *dev,
- {
- unsigned int base_addr_cfg;
- unsigned short base_addr;
-+ u32 rcba_base, bios_cntl;
- int i;
- int ret;
-
-- pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
-- if (!(base_addr_cfg & (1 << 31))) {
-- dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
-- return -ENODEV;
-- }
-- base_addr = (unsigned short)base_addr_cfg;
-- if (base_addr == 0) {
-- dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
-- return -ENODEV;
-- }
-+ /* Clanton does not support iLB SMBUS */
-+ if (id->device != PCI_DEVICE_ID_INTEL_CLANTON_ILB) {
-+ pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
-+ if (!(base_addr_cfg & (1 << 31))) {
-+ dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
-+ return -ENODEV;
-+ }
-+ base_addr = (unsigned short)base_addr_cfg;
-+ if (base_addr == 0) {
-+ dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
-+ return -ENODEV;
-+ }
-
-- smbus_sch_resource.start = base_addr;
-- smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
-+ smbus_sch_resource.start = base_addr;
-+ smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
-+ }
-
- pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
- if (!(base_addr_cfg & (1 << 31))) {
-@@ -132,6 +157,31 @@ static int lpc_sch_probe(struct pci_dev *dev,
- if (ret)
- goto out_dev;
-
-+ /* Add RCBA SPI device */
-+ if (id->device == PCI_DEVICE_ID_INTEL_CLANTON_ILB) {
-+ pci_read_config_dword(dev, LPC_BIOS_CNTL, &bios_cntl);
-+ pr_info("%s BIOS_CNTL 0x%08x\n", __func__, bios_cntl);
-+
-+ /* Enable flash write */
-+ bios_cntl |= LPC_BIOS_CNTL_WE;
-+ pci_write_config_dword(dev, LPC_BIOS_CNTL, bios_cntl);
-+
-+ /* Verify */
-+ pci_read_config_dword(dev, LPC_BIOS_CNTL, &bios_cntl);
-+ pr_info("%s new BIOS_CNTL 0x%08x\n", __func__, bios_cntl);
-+ }
-+
-+ pci_read_config_dword(dev, RCBA_BASE, &rcba_base);
-+ rcba_base &= 0xFFFFC000;
-+ spi_res.start = rcba_base + 0x3020;
-+ spi_res.end = rcba_base + 0x3088;
-+ pr_info("%s RCBA @ 0x%08x\n", __func__, rcba_base);
-+ ret = platform_device_register(&lpc_sch_spi);
-+ if (ret < 0){
-+ pr_err("unable to register %s plat dev\n", lpc_sch_spi.name);
-+ goto out_dev;
-+ }
-+
- 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/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
-index c7dd0cb..4352c6a 100644
---- a/drivers/mmc/host/sdhci-pci.c
-+++ b/drivers/mmc/host/sdhci-pci.c
-@@ -162,6 +162,10 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
- };
-
-+static const struct sdhci_pci_fixes sdhci_intel_cln = {
-+ .quirks = SDHCI_QUIRK_NO_HISPD_BIT,
-+};
-+
- static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot)
- {
- slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
-@@ -777,6 +781,14 @@ static const struct pci_device_id pci_ids[] = {
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = PCI_DEVICE_ID_INTEL_CLN_SD,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .driver_data = (kernel_ulong_t)&sdhci_intel_cln,
-+ },
-+
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRST_SD0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
-diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
-index 46dcb54..7af4129 100644
---- a/drivers/mtd/devices/Kconfig
-+++ b/drivers/mtd/devices/Kconfig
-@@ -159,6 +159,11 @@ config MTD_MTDRAM
- provide storage. You probably want to say 'N' unless you're
- testing stuff.
-
-+config MTD_MTD_CLN_ROM
-+ bool "Simple R/O drive for SPI flash in Clanton x86 legacy block"
-+ help
-+ Driver to enable reading directly from legacy block SPI /sketch part
-+
- config MTDRAM_TOTAL_SIZE
- int "MTDRAM device size in KiB"
- depends on MTD_MTDRAM
-diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
-index 395733a..4c8e399 100644
---- a/drivers/mtd/devices/Makefile
-+++ b/drivers/mtd/devices/Makefile
-@@ -20,5 +20,4 @@ obj-$(CONFIG_MTD_M25P80) += m25p80.o
- obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
- obj-$(CONFIG_MTD_SST25L) += sst25l.o
- obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
--
--CFLAGS_docg3.o += -I$(src)
-\ No newline at end of file
-+CFLAGS_docg3.o += -I$(src)
-diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-index 1164930..4e10f27 100644
---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
-+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-@@ -26,8 +26,8 @@ config STMMAC_PLATFORM
- If unsure, say N.
-
- config STMMAC_PCI
-- bool "STMMAC PCI bus support (EXPERIMENTAL)"
-- depends on STMMAC_ETH && PCI && EXPERIMENTAL
-+ bool "STMMAC PCI bus support"
-+ depends on STMMAC_ETH && PCI
- ---help---
- This is to select the Synopsys DWMAC available on PCI devices,
- if you have a controller with this interface, say Y or M here.
-@@ -54,6 +54,27 @@ config STMMAC_DA
- By default, the DMA arbitration scheme is based on Round-robin
- (rx:tx priority is 1:1).
-
-+config STMMAC_PTP
-+ bool "STMMAC PTP (1588-2005) Clock Support"
-+ default n
-+ depends on EXPERIMENTAL
-+ select PPS
-+ select PTP_1588_CLOCK
-+ ---help---
-+ Say Y here if you want support for 1588 Timestamping with a
-+ Clanton device, using the PTP 1588 Clock support. This is
-+ required to enable timestamping support for the device.
-+
-+ If unsure, say N.
-+
-+config STMMAC_PTP_CLK_MHZ
-+ depends on STMMAC_PTP
-+ int "Reference clock in Mhz"
-+ default 50
-+ ---help---
-+ Frequency if MHz of the reference clock used to derive PTP time
-+ locally. Permissable values are 1 - 255 inclusive
-+
- choice
- prompt "Select the DMA TX/RX descriptor operating modes"
- depends on STMMAC_ETH
-diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
-index c8e8ea6..0995db5 100644
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -3,6 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
- stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
- stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
- stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
-+stmmac-$(CONFIG_STMMAC_PTP) += stmmac_ptp.o
- stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
- dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
- dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
-diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
-index 186d148..ad16e73 100644
---- a/drivers/net/ethernet/stmicro/stmmac/common.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
-@@ -32,9 +32,15 @@
- #include <linux/init.h>
- #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- #define STMMAC_VLAN_TAG_USED
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+#define STMMAC_VLAN_HASH
-+#endif
- #include <linux/if_vlan.h>
- #endif
-
-+#if defined(STMMAC_VLAN_HASH) || defined(CONFIG_STMMAC_PTP)
-+#define STMMAC_ATDS_USED
-+#endif
- #include "descs.h"
- #include "mmc.h"
-
-@@ -319,15 +325,16 @@ struct stmmac_dma_ops {
- void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
- };
-
-+struct stmmac_priv;
- struct stmmac_ops {
- /* MAC core initialization */
- void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
- /* Enable and verify that the IPC module is supported */
-- int (*rx_ipc) (void __iomem *ioaddr);
-+ int (*set_rx_ipc) (void __iomem *ioaddr, bool on);
- /* Dump MAC registers */
- void (*dump_regs) (void __iomem *ioaddr);
- /* Handle extra events on specific interrupts hw dependent */
-- int (*host_irq_status) (void __iomem *ioaddr);
-+ int (*host_irq_status) (struct stmmac_priv * priv);
- /* Multicast filter setting */
- void (*set_filter) (struct net_device *dev, int id);
- /* Flow control setting */
-@@ -340,6 +347,9 @@ struct stmmac_ops {
- unsigned int reg_n);
- void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
- unsigned int reg_n);
-+ /* Enable/Disable VLAN Hash filters */
-+ int (*vlan_rx_add_vid)(struct stmmac_priv *priv, unsigned short vid);
-+ int (*vlan_rx_kill_vid)(struct stmmac_priv *priv, unsigned short vid);
- void (*set_eee_mode) (void __iomem *ioaddr);
- void (*reset_eee_mode) (void __iomem *ioaddr);
- void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
-diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
-index 223adf9..ce08163 100644
---- a/drivers/net/ethernet/stmicro/stmmac/descs.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
-@@ -25,8 +25,8 @@
- #define __DESCS_H__
-
- struct dma_desc {
-- /* Receive descriptor */
- union {
-+ /* Receive descriptor */
- struct {
- /* RDES0 */
- u32 payload_csum_error:1;
-@@ -160,6 +160,49 @@ struct dma_desc {
- } des01;
- unsigned int des2;
- unsigned int des3;
-+
-+ /* Enhanced mode - with VLAN/1588-2005/IPC CHKSUM offload */
-+ #if defined(STMMAC_ATDS_USED)
-+ union {
-+ /* Receive descriptor */
-+ struct {
-+ /* RDES4 */
-+ u32 ip_payload_type:3;
-+ u32 ip_header_error:1;
-+ u32 ip_payload_error:1;
-+ u32 ip_checksum_bypassed:1;
-+ u32 ipv4_packet_received:1;
-+ u32 ipv6_packet_received:1;
-+ u32 message_type:4;
-+ u32 ptp_frame_type:1;
-+ u32 ptp_version:1;
-+ u32 timestamp_dropped:1;
-+ u32 reserved1:1;
-+ u32 av_packet_received:1;
-+ u32 av_tagged_packet_received:1;
-+ u32 vlan_tag_priority_value:3;
-+ u32 reserved2:3;
-+ u32 layer3_filter_match:1;
-+ u32 layer4_filter_match:1;
-+ u32 layer3_layer4_filter_num_matched:2;
-+ u32 reserved3:4;
-+
-+ /* RDES5 */
-+ u32 reserved4;
-+ }erx;
-+
-+ /* Transmit descriptor */
-+ struct {
-+ /* TDES4 */
-+ u32 reserved1;
-+
-+ /* TDES5 */
-+ u32 reserved2;
-+ } etx;
-+ } des05;
-+ unsigned int ts_lo; /* des6 Tx/Rx timestmp lo */
-+ unsigned int ts_hi; /* des7 Tx/Rx timestamp hi */
-+ #endif
- };
-
- /* Transmit checksum insertion control */
-diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
-index 7ad56af..3042098 100644
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
-@@ -50,7 +50,14 @@ enum dwmac1000_irq_status {
- rgmii_irq = 0x0001,
- };
- #define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
--
-+#define GMAC_INT_MASK_LPIIM 0x00000200 /* LPI Interrupt Mask */
-+#define GMAC_INT_MASK_TSIM 0x00000100 /* Timestamp Interrupt Mask */
-+#define GMAC_INT_MASK_PMTIM 0x00000004 /* PMT Interrupt Mask */
-+#define GMAC_INT_MASK_PCSANCIM 0x00000002 /* PCS AN Completion */
-+#define GMAC_INT_MASK_PCSLCHGIM 0x00000001 /* PCS Link Status */
-+#define GMAC_INT_MASK_DEFAULT GMAC_INT_MASK_PCSLCHGIM | GMAC_INT_MASK_PCSANCIM\
-+ | GMAC_INT_MASK_PMTIM | GMAC_INT_MASK_TSIM\
-+ | GMAC_INT_MASK_LPIIM
- /* PMT Control and Status */
- #define GMAC_PMT 0x0000002c
- enum power_event {
-@@ -135,6 +142,7 @@ enum inter_frame_gap {
- #define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
- #define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
- #define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
-+#define GMAC_FRAME_FILTER_VTFE 0x00010000 /* VLAN Tag Filter Enable */
- #define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
- /* GMII ADDR defines */
- #define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
-@@ -145,11 +153,17 @@ enum inter_frame_gap {
- #define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
- #define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
- #define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
--
-+/* GMAC VLAN TAG defines */
-+#define GMAC_VLAN_TAG_VTHM 0x00080000 /* Hash Table Match Enable */
-+#define GMAC_VLAN_TAG_ESVL 0x00040000 /* Enable S-VLAN */
-+#define GMAC_VLAN_TAG_VTIM 0x00020000 /* VLAN Tag inverse match */
-+#define GMAC_VLAN_TAG_ETV 0x00010000 /* Enable 12-bit tag comp */
-+#define GMAC_VLAN_TAG_VLMASK 0x0000FFFF /* VLAN tag ID for Rx frames */
- /*--- DMA BLOCK defines ---*/
- /* DMA Bus Mode register defines */
- #define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
- #define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
-+#define DMA_BUS_MODE_ATDS 0X00000080 /* Alternate Descriptor Size */
- #define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
- #define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
- /* Programmable burst length (passed thorugh platform)*/
-@@ -169,6 +183,7 @@ enum rx_tx_priority_ratio {
- #define DMA_BUS_MODE_USP 0x00800000
- #define DMA_BUS_MODE_PBL 0x01000000
- #define DMA_BUS_MODE_AAL 0x02000000
-+#define DMA_BUS_MODE_RIX 0x80000000
-
- /* DMA CRS Control and Status Register Mapping */
- #define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
-@@ -230,5 +245,50 @@ enum rtc_control {
- #define GMAC_MMC_TX_INTR 0x108
- #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
-
-+/* VLAN Hash register offset */
-+#define GMAC_VLAN_TAG_REP 0x584
-+#define GMAC_VLAN_HASH 0x588
-+#define GMAC_VLAN_HASH_MAXID 0x0F
-+
-+/***************** 1588 regs *****************/
-+#define GMAC_TS_CTRL 0x700 /* Timestamp control reg */
-+#define GMAC_TS_CTRL_TSENA 0x00000001 /* Timestamp enable */
-+#define GMAC_TS_CTRL_TSCFUPDT 0x00000002 /* Timestamp fine/coarse */
-+#define GMAC_TS_CTRL_TSINT 0x00000004 /* Timestamp initialise */
-+#define GMAC_TS_CTRL_TSUPDT 0x00000008 /* Timestamp update */
-+#define GMAC_TS_CTRL_TSTRIG 0x00000010 /* Timestamp trigger en */
-+#define GMAC_TS_CTRL_TSADDREG 0x00000020 /* Timestamp addreg update */
-+#define GMAC_TS_CTRL_TSENALL 0x00000100 /* Timestamp RX enable all */
-+#define GMAC_TS_CTRL_TSCTRLSSR 0x00000200 /* Timestamp rollover ctr */
-+#define GMAC_TS_CTRL_TSVER2ENA 0x00000400 /* Timestamp PTP v2 en */
-+#define GMAC_TS_CTRL_TSIPENA 0x00000800 /* Timestamp PTP over eth */
-+#define GMAC_TS_CTRL_TSIPV6ENA 0x00001000 /* Timestamp over IPV6 */
-+#define GMAC_TS_CTRL_TSIPV4ENA 0x00002000 /* Timestamp over IPV4 */
-+#define GMAC_TS_CTRL_TSEVNTENA 0x00004000 /* Timestamp event only */
-+#define GMAC_TS_CTRL_TSMSTRENA 0x00008000 /* Timestamp master enable */
-+#define GMAC_TS_CTRL_SNTYPSEL0 0x00000000 /* Timestamp type 0 snapshot */
-+#define GMAC_TS_CTRL_SNTYPSEL1 0x00010000 /* Timestamp type 1 snapshot */
-+#define GMAC_TS_CTRL_SNTYPSEL2 0x00020000 /* Timestamp type 2 snapshot */
-+#define GMAC_TS_CTRL_SNTYPSEL3 0x00030000 /* Timestamp type 3 snapshot */
-+#define GMAC_TS_CTRL_TSENMACADR 0x00040000 /* Timestamp mac filter en */
-+#define GMAC_TS_CTRL_ATSFC 0x01000000 /* Timestamp aux fifo clear */
-+#define GMAC_TS_CTRL_ATSEN0 0x02000000 /* Timestamp aux0 snap en */
-+#define GMAC_TS_CTRL_ATSEN1 0x04000000 /* Timestamp aux1 snap en */
-+#define GMAC_TS_CTRL_ATSEN2 0x08000000 /* Timestamp aux2 snap en */
-+#define GMAC_TS_CTRL_ATSEN3 0x10000000 /* Timestamp aux3 enable */
-+#define GMAC_SS_INC 0x704 /* Sub-second increment reg */
-+#define GMAC_ST_SEC 0x708 /* System time seconds */
-+#define GMAC_ST_NSEC 0x70C /* System time nseconds */
-+#define GMAC_ST_SECUP 0x710 /* System time sec-update */
-+#define GMAC_ST_NSECUP 0x714 /* System time nsec-update */
-+#define GMAC_TS_APPEND 0x718 /* Timestamp append */
-+#define GMAC_TT_SEC 0x71C /* Target time seconds */
-+#define GMAC_TT_NSEC 0x720 /* Target time nseconds */
-+#define GMAC_ST_HWSEC 0x724 /* System time high word sec */
-+#define GMAC_ST_TS_STAT 0x728 /* Timestamp status */
-+#define GMAC_PPS_CTRL 0x72C /* PPS signal output control */
-+#define GMAC_AUXTS_NSEC 0x730 /* Aux timestamp counter nsec */
-+#define GMAC_AUXTS_SEC 0x734 /* Aux timestamp counter sec */
-+
- extern const struct stmmac_dma_ops dwmac1000_dma_ops;
- #endif /* __DWMAC1000_H__ */
-diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
-index bfe0226..b6d04ca 100644
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
-@@ -30,6 +30,7 @@
- #include <linux/slab.h>
- #include <asm/io.h>
- #include "dwmac1000.h"
-+#include "stmmac.h"
-
- static void dwmac1000_core_init(void __iomem *ioaddr)
- {
-@@ -38,7 +39,7 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
- writel(value, ioaddr + GMAC_CONTROL);
-
- /* Mask GMAC interrupts */
-- writel(0x207, ioaddr + GMAC_INT_MASK);
-+ writel(GMAC_INT_MASK_DEFAULT, ioaddr + GMAC_INT_MASK);
-
- #ifdef STMMAC_VLAN_TAG_USED
- /* Tag detection without filtering */
-@@ -46,11 +47,15 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
- #endif
- }
-
--static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr)
-+static int dwmac1000_set_rx_ipc(void __iomem *ioaddr, bool on)
- {
- u32 value = readl(ioaddr + GMAC_CONTROL);
-
-- value |= GMAC_CONTROL_IPC;
-+ if(on == true){
-+ value |= GMAC_CONTROL_IPC;
-+ }else{
-+ value &= ~GMAC_CONTROL_IPC;
-+ }
- writel(value, ioaddr + GMAC_CONTROL);
-
- value = readl(ioaddr + GMAC_CONTROL);
-@@ -87,6 +92,7 @@ static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
- static void dwmac1000_set_filter(struct net_device *dev, int id)
- {
- void __iomem *ioaddr = (void __iomem *) dev->base_addr;
-+ struct stmmac_priv *priv = netdev_priv(dev);
- unsigned int value = 0;
- unsigned int perfect_addr_number;
-
-@@ -147,6 +153,10 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
- /* Enable Receive all mode (to debug filtering_fail errors) */
- value |= GMAC_FRAME_FILTER_RA;
- #endif
-+ if (priv->active_vlans != 0){
-+ /* VLAN hash filtering is active on this interface */
-+ value |= GMAC_FRAME_FILTER_VTFE;
-+ }
- writel(value, ioaddr + GMAC_FRAME_FILTER);
-
- CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
-@@ -194,38 +204,42 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
- }
-
-
--static int dwmac1000_irq_status(void __iomem *ioaddr)
-+#ifndef CONFIG_STMMAC_PTP
-+#define stmmac_ptp_check_pps_event(x){}
-+#endif
-+
-+static int dwmac1000_irq_status(struct stmmac_priv *priv)
- {
-- u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
-+ u32 intr_status = readl(priv->ioaddr + GMAC_INT_STATUS);
- int status = 0;
-
- /* Not used events (e.g. MMC interrupts) are not handled. */
- if ((intr_status & mmc_tx_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
-- readl(ioaddr + GMAC_MMC_TX_INTR));
-+ readl(priv->ioaddr + GMAC_MMC_TX_INTR));
- status |= core_mmc_tx_irq;
- }
- if (unlikely(intr_status & mmc_rx_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
-- readl(ioaddr + GMAC_MMC_RX_INTR));
-+ readl(priv->ioaddr + GMAC_MMC_RX_INTR));
- status |= core_mmc_rx_irq;
- }
- if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
-- readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
-+ readl(priv->ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
- status |= core_mmc_rx_csum_offload_irq;
- }
- if (unlikely(intr_status & pmt_irq)) {
- CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
- /* clear the PMT bits 5 and 6 by reading the PMT
- * status register. */
-- readl(ioaddr + GMAC_PMT);
-+ readl(priv->ioaddr + GMAC_PMT);
- status |= core_irq_receive_pmt_irq;
- }
- /* MAC trx/rx EEE LPI entry/exit interrupts */
- if (intr_status & lpiis_irq) {
- /* Clean LPI interrupt by reading the Reg 12 */
-- u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
-+ u32 lpi_status = readl(priv->ioaddr + LPI_CTRL_STATUS);
-
- if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
- CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
-@@ -244,10 +258,110 @@ static int dwmac1000_irq_status(void __iomem *ioaddr)
- status |= core_irq_rx_path_exit_lpi_mode;
- }
- }
-+ if (unlikely(intr_status & time_stamp_irq)){
-+ stmmac_ptp_check_pps_event(priv);
-+ }
-
- return status;
- }
-
-+static unsigned int dwmac1000_calc_vlan_4bit_crc ( const char * vlan )
-+{
-+ int i = 0, j = 0, len = 0, bit = 0;
-+ unsigned int crc = 0xFFFFFFFF;
-+ unsigned int poly = 0x04C11DB7;
-+ unsigned char data;
-+
-+ if(unlikely(vlan == NULL)){
-+ return 0;
-+ }
-+
-+ for( i = 0; i < 2; i++ ) {
-+ data = vlan[i];
-+
-+ if (i==0){
-+ len = 8;
-+ }else{
-+ len = 4;
-+ }
-+
-+ for( bit = 0; bit < len; bit++ ) {
-+
-+ j = ((crc >> 31) ^ data) & 0x1;
-+ crc <<= 1;
-+
-+ if( j != 0 ){
-+ crc ^= poly;
-+ }
-+
-+ data >>= 1;
-+ }
-+ }
-+ return crc;
-+
-+}
-+
-+static int dwmac1000_vlan_rx_add_vid(struct stmmac_priv *priv, unsigned short vid)
-+{
-+ u32 reg = 0;
-+ u32 bit_nr = 0;
-+
-+ if(unlikely(priv == NULL || vid > GMAC_VLAN_HASH_MAXID)){
-+ return -EINVAL;
-+ }
-+
-+ if(priv->active_vlans == 0){
-+
-+ /* Flip the VTFE bit in GMAC_FRAME_FILTER */
-+ reg = readl(priv->ioaddr + GMAC_FRAME_FILTER);
-+ reg |= GMAC_FRAME_FILTER_VTFE;
-+ writel(reg, priv->ioaddr + GMAC_FRAME_FILTER);
-+
-+ /* Enable hash filtering - based on 12 bit vid */
-+ reg = readl(priv->ioaddr + GMAC_VLAN_TAG);
-+ reg |= GMAC_VLAN_TAG_VTHM | GMAC_VLAN_TAG_ETV | 0x0000FFFF;
-+ writel(reg, priv->ioaddr + GMAC_VLAN_TAG);
-+ }
-+
-+ bit_nr = (~dwmac1000_calc_vlan_4bit_crc((const char*)&vid)) >> 28;
-+ priv->active_vlans |= 1 << bit_nr;
-+
-+ writel(priv->active_vlans, priv->ioaddr + GMAC_VLAN_HASH);
-+
-+ return 0;
-+}
-+
-+static int dwmac1000_vlan_rx_kill_vid(struct stmmac_priv *priv, unsigned short vid)
-+{
-+ u32 reg = 0;
-+ u32 bit_nr = 0;
-+
-+ if(unlikely(priv == NULL || vid > GMAC_VLAN_HASH_MAXID)){
-+ return -EINVAL;
-+ }
-+
-+ bit_nr = (~dwmac1000_calc_vlan_4bit_crc((const char*)&vid)) >> 28;
-+
-+ priv->active_vlans &= ~(1 << bit_nr);
-+ writel(priv->active_vlans, priv->ioaddr + GMAC_VLAN_HASH);
-+
-+ if(priv->active_vlans == 0){
-+
-+ /* Disable hash filtering */
-+ reg = readl(priv->ioaddr + GMAC_VLAN_TAG);
-+ reg &= ~(GMAC_VLAN_TAG_VTHM | GMAC_VLAN_TAG_ETV | 0x00000001);
-+ writel(reg, priv->ioaddr + GMAC_VLAN_TAG);
-+
-+ /* Flip the VTFE bit in GMAC_FRAME_FILTER */
-+ reg = readl(priv->ioaddr + GMAC_FRAME_FILTER);
-+ reg &= ~GMAC_FRAME_FILTER_VTFE;
-+ writel(reg, priv->ioaddr + GMAC_FRAME_FILTER);
-+
-+ }
-+
-+ return 0;
-+}
-+
- static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
- {
- u32 value;
-@@ -297,9 +411,10 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
- writel(value, ioaddr + LPI_TIMER_CTRL);
- }
-
-+
- static const struct stmmac_ops dwmac1000_ops = {
- .core_init = dwmac1000_core_init,
-- .rx_ipc = dwmac1000_rx_ipc_enable,
-+ .set_rx_ipc = dwmac1000_set_rx_ipc,
- .dump_regs = dwmac1000_dump_regs,
- .host_irq_status = dwmac1000_irq_status,
- .set_filter = dwmac1000_set_filter,
-@@ -307,6 +422,8 @@ static const struct stmmac_ops dwmac1000_ops = {
- .pmt = dwmac1000_pmt,
- .set_umac_addr = dwmac1000_set_umac_addr,
- .get_umac_addr = dwmac1000_get_umac_addr,
-+ .vlan_rx_add_vid = dwmac1000_vlan_rx_add_vid,
-+ .vlan_rx_kill_vid = dwmac1000_vlan_rx_kill_vid,
- .set_eee_mode = dwmac1000_set_eee_mode,
- .reset_eee_mode = dwmac1000_reset_eee_mode,
- .set_eee_timer = dwmac1000_set_eee_timer,
-diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
-index bf83c03..a0c08e1 100644
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
-@@ -59,9 +59,12 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
- * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
- * depending on pbl value.
- */
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ value = DMA_BUS_MODE_RIX | (pbl << DMA_BUS_MODE_PBL_SHIFT);
-+#else
- value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
- (pbl << DMA_BUS_MODE_RPBL_SHIFT));
--
-+#endif
- /* Set the Fixed burst mode */
- if (fb)
- value |= DMA_BUS_MODE_FB;
-@@ -70,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
- if (mb)
- value |= DMA_BUS_MODE_MB;
-
-+#if defined(STMMAC_ATDS_USED)
-+ value |= DMA_BUS_MODE_ATDS;
-+#endif
-+
- #ifdef CONFIG_STMMAC_DA
- value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
- #endif
-diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
-index f83210e..43472c0 100644
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
-@@ -67,12 +67,12 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
- readl(ioaddr + MAC_VLAN2));
- }
-
--static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
-+static int dwmac100_set_rx_ipc(void __iomem *ioaddr, bool on)
- {
- return 0;
- }
-
--static int dwmac100_irq_status(void __iomem *ioaddr)
-+static int dwmac100_irq_status(struct stmmac_priv *priv)
- {
- return 0;
- }
-@@ -160,7 +160,7 @@ static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
-
- static const struct stmmac_ops dwmac100_ops = {
- .core_init = dwmac100_core_init,
-- .rx_ipc = dwmac100_rx_ipc_enable,
-+ .set_rx_ipc = dwmac100_set_rx_ipc,
- .dump_regs = dwmac100_dump_mac_regs,
- .host_irq_status = dwmac100_irq_status,
- .set_filter = dwmac100_set_filter,
-diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
-index 0c74a70..50617c5 100644
---- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
-@@ -149,6 +149,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
- {
- writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
- writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
-+ writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);
- }
-
- /* This reads the MAC core counters (if actaully supported).
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-index b05df89..611f70e 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-@@ -27,9 +27,11 @@
- #define DRV_MODULE_VERSION "Nov_2012"
-
- #include <linux/clk.h>
-+#include <linux/clocksource.h>
- #include <linux/stmmac.h>
- #include <linux/phy.h>
- #include <linux/pci.h>
-+#include <linux/ptp_clock_kernel.h>
- #include "common.h"
-
- struct stmmac_priv {
-@@ -72,8 +74,22 @@ struct stmmac_priv {
- u32 msg_enable;
- spinlock_t lock;
- spinlock_t tx_lock;
-+
-+ /* PTP */
-+ struct ptp_clock *ptp_clock;
-+ struct ptp_clock_info ptp_caps;
-+ struct delayed_work overflow_work;
-+ spinlock_t tmreg_lock;
-+ struct cyclecounter ccnt;
-+ struct timecounter tcnt;
-+// struct timecompare tcmp;
-+ int hwts;
-+ struct stmmac_timer *tm;
-+
- int wolopts;
- int wol_irq;
-+
-+ int active_vlans;
- struct plat_stmmacenet_data *plat;
- struct stmmac_counters mmc;
- struct dma_features dma_cap;
-@@ -81,6 +97,8 @@ struct stmmac_priv {
- struct clk *stmmac_clk;
- int clk_csr;
- int synopsys_id;
-+ int irqmode_msi;
-+ struct pci_dev * pdev;
- struct timer_list eee_ctrl_timer;
- bool tx_path_in_lpi_mode;
- int lpi_irq;
-@@ -110,6 +128,63 @@ int stmmac_dvr_remove(struct net_device *ndev);
- struct stmmac_priv *stmmac_dvr_probe(struct device *device,
- struct plat_stmmacenet_data *plat_dat,
- void __iomem *addr);
-+#ifdef CONFIG_STMMAC_PTP
-+
-+#define STMMAC_PTP_OVERFLOW_CHECK_ENABLED (u32)(1)
-+#define STMMAC_PTP_PPS_ENABLED (u32)(1 << 1)
-+#define STMMAC_PTP_HWTS_TX_EN (u32)(1 << 2)
-+#define STMMAC_PTP_HWTS_RX_EN (u32)(1 << 3)
-+
-+extern void stmmac_ptp_init(struct net_device *ndev, struct device * pdev);
-+extern void stmmac_ptp_remove(struct stmmac_priv *priv);
-+extern int stmmac_ptp_hwtstamp_ioctl(struct stmmac_priv *priv,
-+ struct ifreq *ifr, int cmd);
-+extern void stmmac_ptp_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
-+ struct sk_buff *skb);
-+extern void stmmac_ptp_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
-+ struct sk_buff *skb);
-+extern void stmmac_ptp_check_pps_event(struct stmmac_priv *priv);
-+#endif
-+
-+#ifdef CONFIG_HAVE_CLK
-+static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-+{
-+ if (!IS_ERR(priv->stmmac_clk))
-+ return clk_prepare_enable(priv->stmmac_clk);
-+
-+ return 0;
-+}
-+
-+static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-+{
-+ if (IS_ERR(priv->stmmac_clk))
-+ return;
-+
-+ clk_disable_unprepare(priv->stmmac_clk);
-+}
-+static inline int stmmac_clk_get(struct stmmac_priv *priv)
-+{
-+ priv->stmmac_clk = clk_get(priv->device, NULL);
-+
-+ if (IS_ERR(priv->stmmac_clk))
-+ return PTR_ERR(priv->stmmac_clk);
-+
-+ return 0;
-+}
-+#else
-+static inline int stmmac_clk_enable(struct stmmac_priv *priv)
-+{
-+ return 0;
-+}
-+static inline void stmmac_clk_disable(struct stmmac_priv *priv)
-+{
-+}
-+static inline int stmmac_clk_get(struct stmmac_priv *priv)
-+{
-+ return 0;
-+}
-+#endif /* CONFIG_HAVE_CLK */
-+
- void stmmac_disable_eee_mode(struct stmmac_priv *priv);
- bool stmmac_eee_init(struct stmmac_priv *priv);
-
-@@ -167,6 +242,7 @@ static inline int stmmac_register_pci(void)
- static inline void stmmac_unregister_pci(void)
- {
- }
-+
- #endif /* CONFIG_STMMAC_PCI */
-
- #endif /* __STMMAC_H__ */
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
-index 1372ce2..0644dcd 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
-@@ -31,6 +31,7 @@
-
- #include "stmmac.h"
- #include "dwmac_dma.h"
-+#include "dwmac1000.h"
-
- #define REG_SPACE_SIZE 0x1054
- #define MAC100_ETHTOOL_NAME "st_mac100"
-@@ -231,9 +232,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
- return -EBUSY;
- }
- cmd->transceiver = XCVR_INTERNAL;
-- spin_lock_irq(&priv->lock);
- rc = phy_ethtool_gset(phy, cmd);
-- spin_unlock_irq(&priv->lock);
- return rc;
- }
-
-@@ -244,10 +243,7 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
- struct phy_device *phy = priv->phydev;
- int rc;
-
-- spin_lock(&priv->lock);
- rc = phy_ethtool_sset(phy, cmd);
-- spin_unlock(&priv->lock);
--
- return rc;
- }
-
-@@ -279,7 +275,7 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
- static void stmmac_ethtool_gregs(struct net_device *dev,
- struct ethtool_regs *regs, void *space)
- {
-- int i;
-+ int i, offset = 0;
- u32 *reg_space = (u32 *) space;
-
- struct stmmac_priv *priv = netdev_priv(dev);
-@@ -300,9 +296,20 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
- /* MAC registers */
- for (i = 0; i < 55; i++)
- reg_space[i] = readl(priv->ioaddr + (i * 4));
-+
-+ /* VLAN registers */
-+ offset = i;
-+ reg_space[offset++] = readl(priv->ioaddr + GMAC_VLAN_TAG_REP);
-+ reg_space[offset++] = readl(priv->ioaddr + GMAC_VLAN_HASH);
-+
-+ /* 1588 registers */
-+ for(i = 0; i < 13; i++);
-+ reg_space[i + offset] = readl(priv->ioaddr + (GMAC_TS_CTRL + (i * 4)));
-+
- /* DMA registers */
-+ offset += i;
- for (i = 0; i < 22; i++)
-- reg_space[i + 55] =
-+ reg_space[i + offset] =
- readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
- }
- }
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-index b75f4b2..f74b542 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -28,6 +28,9 @@
- https://bugzilla.stlinux.com/
- *******************************************************************************/
-
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+#include <asm/cln.h>
-+#endif
- #include <linux/clk.h>
- #include <linux/kernel.h>
- #include <linux/interrupt.h>
-@@ -135,6 +138,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
- #ifdef CONFIG_STMMAC_DEBUG_FS
- static int stmmac_init_fs(struct net_device *dev);
- static void stmmac_exit_fs(void);
-+static int debugfs_registered = 0;
-+
- #endif
-
- #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
-@@ -502,13 +507,29 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
- }
-
- /**
-+ * init_dma_err_cleanup
-+ *
-+ * @dev: net device to clean
-+ * Description: Does a cleanup if kmalloc fails during init
-+ */
-+static void init_dma_err_cleanup(struct stmmac_priv * priv)
-+{
-+ if (priv->tx_skbuff != NULL)
-+ kfree(priv->tx_skbuff);
-+ if (priv->rx_skbuff_dma != NULL)
-+ kfree (priv->rx_skbuff_dma);
-+ if (priv->rx_skbuff != NULL)
-+ kfree (priv->rx_skbuff);
-+}
-+
-+/**
- * init_dma_desc_rings - init the RX/TX descriptor rings
- * @dev: net device structure
- * Description: this function initializes the DMA RX/TX descriptors
- * and allocates the socket buffers. It suppors the chained and ring
- * modes.
- */
--static void init_dma_desc_rings(struct net_device *dev)
-+static int init_dma_desc_rings(struct net_device *dev)
- {
- int i;
- struct stmmac_priv *priv = netdev_priv(dev);
-@@ -532,8 +553,16 @@ static void init_dma_desc_rings(struct net_device *dev)
- txsize, rxsize, bfsize);
-
- priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
-+ if (priv->rx_skbuff_dma == NULL)
-+ return -ENOMEM;
-+
- priv->rx_skbuff =
- kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
-+ if (priv->rx_skbuff == NULL){
-+ init_dma_err_cleanup(priv);
-+ return -ENOMEM;
-+ }
-+
- priv->dma_rx =
- (struct dma_desc *)dma_alloc_coherent(priv->device,
- rxsize *
-@@ -542,6 +571,11 @@ static void init_dma_desc_rings(struct net_device *dev)
- GFP_KERNEL);
- priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
- GFP_KERNEL);
-+ if (priv->tx_skbuff == NULL){
-+ init_dma_err_cleanup(priv);
-+ return -ENOMEM;
-+ }
-+
- priv->dma_tx =
- (struct dma_desc *)dma_alloc_coherent(priv->device,
- txsize *
-@@ -550,8 +584,9 @@ static void init_dma_desc_rings(struct net_device *dev)
- GFP_KERNEL);
-
- if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) {
-+ init_dma_err_cleanup(priv);
- pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__);
-- return;
-+ return -ENOMEM;
- }
-
- DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
-@@ -569,8 +604,9 @@ static void init_dma_desc_rings(struct net_device *dev)
- skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
- GFP_KERNEL);
- if (unlikely(skb == NULL)) {
-+ init_dma_err_cleanup(priv);
- pr_err("%s: Rx init fails; skb is NULL\n", __func__);
-- break;
-+ return -ENOMEM;
- }
- skb_reserve(skb, NET_IP_ALIGN);
- priv->rx_skbuff[i] = skb;
-@@ -615,6 +651,8 @@ static void init_dma_desc_rings(struct net_device *dev)
- pr_info("TX descriptor ring:\n");
- display_ring(priv->dma_tx, txsize);
- }
-+
-+ return 0;
- }
-
- static void dma_free_rx_skbufs(struct stmmac_priv *priv)
-@@ -736,6 +774,10 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
- DMA_TO_DEVICE);
- priv->hw->ring->clean_desc3(p);
-
-+#ifdef CONFIG_STMMAC_PTP
-+ stmmac_ptp_tx_hwtstamp(priv, p, skb);
-+#endif
-+
- if (likely(skb != NULL)) {
- dev_kfree_skb(skb);
- priv->tx_skbuff[entry] = NULL;
-@@ -963,6 +1005,25 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
- }
-
- /**
-+ * stmmac_hw_set_rx_ipc
-+ * @priv : pointer to the private device structure.
-+ * Enables RX IPC offload if the feature is supported in hardware
-+ */
-+static int stmmac_hw_set_rx_ipc(struct stmmac_priv *priv, bool on)
-+{
-+ int ret = 0;
-+
-+ /* Enable the IPC (Checksum Offload) and check if the feature has been
-+ * enabled during the core configuration. */
-+ ret = priv->hw->mac->set_rx_ipc(priv->ioaddr, on);
-+ if (on == true && !ret) {
-+ pr_warning(" RX IPC Checksum Offload not configured.\n");
-+ priv->plat->rx_coe = STMMAC_RX_COE_NONE;
-+ }
-+ return ret;
-+}
-+
-+/**
- * stmmac_tx_timer:
- * @data: data pointer
- * Description:
-@@ -1022,7 +1083,12 @@ static int stmmac_open(struct net_device *dev)
- priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
- priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
- priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
-- init_dma_desc_rings(dev);
-+ ret = init_dma_desc_rings(dev);
-+ if (ret < 0){
-+ pr_err("%s: DMA initialization failed\n", __func__);
-+ goto open_error;
-+ }
-+
-
- /* DMA initialization and SW reset */
- ret = stmmac_init_dma_engine(priv);
-@@ -1078,6 +1144,9 @@ static int stmmac_open(struct net_device *dev)
- /* Set the HW DMA mode and the COE */
- stmmac_dma_operation_mode(priv);
-
-+ /* Enable RX IPC if supported by silicon */
-+ ret = stmmac_hw_set_rx_ipc(priv, true);
-+
- /* Extra statistics */
- memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
- priv->xstats.threshold = tc;
-@@ -1085,9 +1154,12 @@ static int stmmac_open(struct net_device *dev)
- stmmac_mmc_setup(priv);
-
- #ifdef CONFIG_STMMAC_DEBUG_FS
-- ret = stmmac_init_fs(dev);
-- if (ret < 0)
-- pr_warning("%s: failed debugFS registration\n", __func__);
-+ if (debugfs_registered == 0){
-+ debugfs_registered = 1;
-+ ret = stmmac_init_fs(dev);
-+ if (ret < 0)
-+ pr_warning("%s: failed debugFS registration\n", __func__);
-+ }
- #endif
- /* Start the ball rolling... */
- DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
-@@ -1430,6 +1502,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
- #endif
- skb->protocol = eth_type_trans(skb, priv->dev);
-
-+#ifdef CONFIG_STMMAC_PTP
-+ stmmac_ptp_tx_hwtstamp(priv, priv->dma_rx + entry, skb);
-+#endif
- if (unlikely(!priv->plat->rx_coe))
- skb_checksum_none_assert(skb);
- else
-@@ -1588,9 +1663,19 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
- if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
- features &= ~NETIF_F_ALL_CSUM;
-
-+ stmmac_hw_set_rx_ipc(priv, features & NETIF_F_RXCSUM);
-+
- return features;
- }
-
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+ #define mask_pvm(x) cln_pci_pvm_mask(x)
-+ #define unmask_pvm(x) cln_pci_pvm_unmask(x)
-+#else
-+ #define mask_pvm(x)
-+ #define unmask_pvm(x)
-+#endif
-+
- static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
- {
- struct net_device *dev = (struct net_device *)dev_id;
-@@ -1601,10 +1686,12 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
- return IRQ_NONE;
- }
-
-+ mask_pvm(priv->pdev);
-+
- /* To handle GMAC own interrupts */
- if (priv->plat->has_gmac) {
-- int status = priv->hw->mac->host_irq_status((void __iomem *)
-- dev->base_addr);
-+ int status = priv->hw->mac->host_irq_status(priv);
-+
- if (unlikely(status)) {
- if (status & core_mmc_tx_irq)
- priv->xstats.mmc_tx_irq_n++;
-@@ -1634,6 +1721,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
- /* To handle DMA interrupts */
- stmmac_dma_interrupt(priv);
-
-+ unmask_pvm(priv->pdev);
-+
- return IRQ_HANDLED;
- }
-
-@@ -1669,7 +1758,15 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
- if (!priv->phydev)
- return -EINVAL;
-
-- ret = phy_mii_ioctl(priv->phydev, rq, cmd);
-+ switch (cmd) {
-+#ifdef CONFIG_STMMAC_PTP
-+ case SIOCSHWTSTAMP:
-+ ret = stmmac_ptp_hwtstamp_ioctl(priv, rq, cmd);
-+ break;
-+#endif
-+ default:
-+ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
-+ }
-
- return ret;
- }
-@@ -1850,6 +1947,21 @@ static void stmmac_exit_fs(void)
- }
- #endif /* CONFIG_STMMAC_DEBUG_FS */
-
-+#ifdef STMMAC_VLAN_HASH
-+static int stmmac_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
-+{
-+ struct stmmac_priv *priv = netdev_priv(dev);
-+ return priv->hw->mac->vlan_rx_add_vid(priv, vid);
-+}
-+
-+static int stmmac_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
-+{
-+ struct stmmac_priv *priv = netdev_priv(dev);
-+ return priv->hw->mac->vlan_rx_kill_vid(priv, vid);
-+}
-+
-+#endif
-+
- static const struct net_device_ops stmmac_netdev_ops = {
- .ndo_open = stmmac_open,
- .ndo_start_xmit = stmmac_xmit,
-@@ -1860,6 +1972,10 @@ static const struct net_device_ops stmmac_netdev_ops = {
- .ndo_tx_timeout = stmmac_tx_timeout,
- .ndo_do_ioctl = stmmac_ioctl,
- .ndo_set_config = stmmac_config,
-+#ifdef STMMAC_VLAN_HASH
-+ .ndo_vlan_rx_add_vid = stmmac_vlan_rx_add_vid,
-+ .ndo_vlan_rx_kill_vid = stmmac_vlan_rx_kill_vid,
-+#endif
- #ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = stmmac_poll_controller,
- #endif
-@@ -1924,13 +2040,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
- /* Select the enhnaced/normal descriptor structures */
- stmmac_selec_desc_mode(priv);
-
-- /* Enable the IPC (Checksum Offload) and check if the feature has been
-- * enabled during the core configuration. */
-- ret = priv->hw->mac->rx_ipc(priv->ioaddr);
-- if (!ret) {
-- pr_warning(" RX IPC Checksum Offload not configured.\n");
-- priv->plat->rx_coe = STMMAC_RX_COE_NONE;
-- }
-+ ret = stmmac_hw_set_rx_ipc(priv, true);
-
- if (priv->plat->rx_coe)
- pr_info(" RX Checksum Offload Engine supported (type %d)\n",
-@@ -2001,6 +2111,12 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
- /* Both mac100 and gmac support receive VLAN tag detection */
- ndev->features |= NETIF_F_HW_VLAN_RX;
- #endif
-+#ifdef STMMAC_VLAN_HASH
-+ ndev->features |= NETIF_F_HW_VLAN_FILTER;
-+ ndev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-+ NETIF_F_RXCSUM;
-+#endif
-+
- priv->msg_enable = netif_msg_init(debug, default_msg_level);
-
- if (flow_ctrl)
-@@ -2044,6 +2160,10 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
- else
- priv->clk_csr = priv->plat->clk_csr;
-
-+#ifdef CONFIG_STMMAC_PTP
-+ stmmac_ptp_init(ndev, device);
-+#endif
-+
- /* MDIO bus Registration */
- ret = stmmac_mdio_register(ndev);
- if (ret < 0) {
-@@ -2060,6 +2180,9 @@ error_clk_get:
- unregister_netdev(ndev);
- error_netdev_register:
- netif_napi_del(&priv->napi);
-+#ifdef CONFIG_STMMAC_PTP
-+ stmmac_ptp_remove(priv);
-+#endif
- free_netdev(ndev);
-
- return NULL;
-@@ -2075,7 +2198,7 @@ int stmmac_dvr_remove(struct net_device *ndev)
- {
- struct stmmac_priv *priv = netdev_priv(ndev);
-
-- pr_info("%s:\n\tremoving driver", __func__);
-+ pr_info("%s:\n\tremoving driver\n", __func__);
-
- priv->hw->dma->stop_rx(priv->ioaddr);
- priv->hw->dma->stop_tx(priv->ioaddr);
-@@ -2083,6 +2206,10 @@ int stmmac_dvr_remove(struct net_device *ndev)
- stmmac_set_mac(priv->ioaddr, false);
- stmmac_mdio_unregister(ndev);
- netif_carrier_off(ndev);
-+
-+#ifdef CONFIG_STMMAC_PTP
-+ stmmac_ptp_remove(priv);
-+#endif
- unregister_netdev(ndev);
- 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..bc1a2a5 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
-@@ -23,32 +23,194 @@
- Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
- *******************************************************************************/
-
-+#include <linux/dmi.h>
- #include <linux/pci.h>
-+#include <linux/platform_data/clanton.h>
- #include "stmmac.h"
-
--struct plat_stmmacenet_data plat_dat;
--struct stmmac_mdio_bus_data mdio_data;
--struct stmmac_dma_cfg dma_cfg;
-+/* List of supported PCI device IDs */
-+#define STMMAC_VENDOR_ID 0x700
-+#define STMMAC_DEVICE_ID 0x1108
-+#define STMMAC_CLANTON_ID 0x0937
-+#define MAX_INTERFACES 0x02
-+
-+#if defined (CONFIG_INTEL_QUARK_X1000_SOC)
-+static int enable_msi = 1;
-+#else
-+static int enable_msi = 0;
-+#endif
-+module_param(enable_msi, int, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
-+
-+static int bus_id = 1;
-+static char stmmac_mac_data[MAX_INTERFACES][ETH_ALEN];
-+
-+struct stmmac_cln_mac_data {
-+ int phy_addr;
-+ int bus_id;
-+ const char * name;
-+};
-+
-+static struct stmmac_cln_mac_data phy_data [] = {
-+ {
-+ .phy_addr = -1, /* not connected */
-+ .bus_id = 1,
-+ .name = "QuarkEmulation",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 2,
-+ .name = "QuarkEmulation",
-+ },
-+ {
-+ .phy_addr = 3,
-+ .bus_id = 1,
-+ .name = "ClantonPeakSVP",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 2,
-+ .name = "ClantonPeakSVP",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 1,
-+ .name = "KipsBay",
-+ },
-+ {
-+ .phy_addr = -1, /* not connected */
-+ .bus_id = 2,
-+ .name = "KipsBay",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 1,
-+ .name = "CrossHill",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 2,
-+ .name = "CrossHill",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 1,
-+ .name = "ClantonHill",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 2,
-+ .name = "ClantonHill",
-+ },
-+ {
-+ .phy_addr = 1,
-+ .bus_id = 1,
-+ .name = "Galileo",
-+ },
-+ {
-+ .phy_addr = -1, /* not connected */
-+ .bus_id = 2,
-+ .name = "Galileo",
-+ },
-+};
-+
-+
-+static int stmmac_find_phy_addr(int mdio_bus_id)
-+{
-+ int i = 0;
-+ const char * board_name = dmi_get_system_info(DMI_BOARD_NAME);
-+ if (board_name == NULL)
-+ return -1;
-+
-+ for (; i < sizeof(phy_data)/sizeof(struct stmmac_cln_mac_data); i++){
-+ if ((!strcmp(phy_data[i].name, board_name)) &&
-+ phy_data[i].bus_id == mdio_bus_id)
-+ return phy_data[i].phy_addr;
-+ }
-+
-+ 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));
-+
-+ plat_dat->mdio_bus_data = kzalloc(sizeof(struct stmmac_mdio_bus_data),
-+ GFP_KERNEL);
-+ if (plat_dat->mdio_bus_data == NULL)
-+ return -ENOMEM;
-+
-+ plat_dat->dma_cfg = kzalloc(sizeof(struct stmmac_dma_cfg),GFP_KERNEL);
-+ if (plat_dat->dma_cfg == NULL)
-+ return -ENOMEM;
-+
-+ if (id->device == STMMAC_CLANTON_ID) {
-+
-+ phy_addr = stmmac_find_phy_addr(mdio_bus_id);
-+ if (phy_addr == -1)
-+ return -ENODEV;
-+
-+ plat_dat->bus_id = mdio_bus_id;
-+ plat_dat->phy_addr = phy_addr;
-+ plat_dat->interface = PHY_INTERFACE_MODE_RMII;
-+ /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
-+ plat_dat->clk_csr = 2;
-+ plat_dat->has_gmac = 1;
-+ plat_dat->force_sf_dma_mode = 1;
-+
-+ plat_dat->mdio_bus_data->phy_reset = NULL;
-+ plat_dat->mdio_bus_data->phy_mask = 0;
-+
-+ plat_dat->dma_cfg->pbl = 16;
-+ plat_dat->dma_cfg->fixed_burst = 1;
-+ plat_dat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
-+
-+ } else {
-+
-+ plat_dat->bus_id = mdio_bus_id;
-+ plat_dat->phy_addr = phy_addr;
-+ plat_dat->interface = PHY_INTERFACE_MODE_GMII;
-+ /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
-+ plat_dat->clk_csr = 2;
-+ plat_dat->has_gmac = 1;
-+ plat_dat->force_sf_dma_mode = 1;
-+
-+ plat_dat->mdio_bus_data->phy_reset = NULL;
-+ plat_dat->mdio_bus_data->phy_mask = 0;
-+
-+ plat_dat->dma_cfg->pbl = 32;
-+ plat_dat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
-+
-+ }
-+
-+ return 0;
- }
-
-+#if 0
-+/**
-+ * stmmac_pci_find_mac
-+ *
-+ * @prive: pointer to private stmmac structure
-+ * @mdio_bus_id : MDIO bus identifier used to find the platform MAC id
-+ *
-+ * Attempt to find MAC in platform data. If not found then driver will generate
-+ * a random one for itself in any case
-+ */
-+void stmmac_pci_find_mac (struct stmmac_priv * priv, unsigned int mdio_bus_id)
-+{
-+ unsigned int id = mdio_bus_id - 1;
-+ if (priv == NULL || id >= MAX_INTERFACES)
-+ return;
-+
-+ if (intel_cln_plat_get_mac(PLAT_DATA_MAC0+id,
-+ (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,
- int ret = 0;
- void __iomem *addr = NULL;
- struct stmmac_priv *priv = NULL;
-+ struct plat_stmmacenet_data *plat_dat = NULL;
- int i;
-
-+ plat_dat = kmalloc(sizeof(struct plat_stmmacenet_data), GFP_KERNEL);
-+ if (plat_dat == NULL){
-+ ret = -ENOMEM;
-+ goto err_out_map_failed;
-+ }
-+
-+ /* return -ENODEV for non existing PHY, stop probing here */
-+ ret = stmmac_default_data(plat_dat, bus_id, id);
-+ if (ret != 0)
-+ goto err_platdata;
-+
-+
- /* Enable pci device */
- ret = pci_enable_device(pdev);
- if (ret) {
-@@ -96,30 +271,51 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
- break;
- }
- pci_set_master(pdev);
-+ if(enable_msi == 1){
-+ pci_enable_msi(pdev);
-+ pr_info("stmmac MSI mode enabled");
-+ }
-
-- stmmac_default_data();
-+ pr_info("Vendor 0x%04x Device 0x%04x\n",
-+ id->vendor, id->device);
-
-- priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
-+ priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
- if (!priv) {
- pr_err("%s: main driver probe failed", __func__);
- goto err_out;
- }
-+#if 0
-+ stmmac_pci_find_mac(priv, bus_id);
-+#endif
- priv->dev->irq = pdev->irq;
- priv->wol_irq = pdev->irq;
--
-+ priv->irqmode_msi = enable_msi;
-+ priv->pdev = pdev;
-+ #ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ priv->lpi_irq = -ENXIO;
-+ #endif
- pci_set_drvdata(pdev, priv->dev);
-
- pr_debug("STMMAC platform driver registration completed");
-+ bus_id++;
-
- return 0;
-
- err_out:
- pci_clear_master(pdev);
--err_out_map_failed:
- pci_release_regions(pdev);
- err_out_req_reg_failed:
- pci_disable_device(pdev);
--
-+err_platdata:
-+ if (plat_dat != NULL){
-+ if (plat_dat->dma_cfg != NULL)
-+ kfree (plat_dat->dma_cfg);
-+ if (plat_dat->mdio_bus_data != NULL)
-+ kfree (plat_dat->mdio_bus_data);
-+ kfree(plat_dat);
-+ }
-+err_out_map_failed:
-+ bus_id++;
- return ret;
- }
-
-@@ -138,6 +334,21 @@ static void stmmac_pci_remove(struct pci_dev *pdev)
- stmmac_dvr_remove(ndev);
-
- pci_set_drvdata(pdev, NULL);
-+
-+ if(enable_msi == 1) {
-+ if(pci_dev_msi_enabled(pdev)) {
-+ pci_disable_msi(pdev);
-+ }
-+ }
-+
-+ if (priv->plat != NULL) {
-+ if (priv->plat->dma_cfg != NULL)
-+ kfree (priv->plat->dma_cfg);
-+ if (priv->plat->mdio_bus_data != NULL)
-+ kfree (priv->plat->mdio_bus_data);
-+ kfree(priv->plat);
-+ }
-+
- 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)
- }
- #endif
-
--#define STMMAC_VENDOR_ID 0x700
--#define STMMAC_DEVICE_ID 0x1108
--
- static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = {
- {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
- {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
-+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, STMMAC_CLANTON_ID)},
- {}
- };
-
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
-new file mode 100644
-index 0000000..8552d0c
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
-@@ -0,0 +1,723 @@
-+/*******************************************************************************
-+
-+ STMMAC 1588-2005 hardware accel
-+ Copyright(c) 2012 Intel Corporation. This code is based on IXGBE_PTP
-+
-+ This program is free software; you can redistribute it and/or modify it
-+ under the terms and conditions of the GNU General Public License,
-+ version 2, as published by the Free Software Foundation.
-+
-+ This program is distributed in the hope it will be useful, but WITHOUT
-+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
-+ more details.
-+
-+ You should have received a copy of the GNU General Public License along with
-+ this program; if not, write to the Free Software Foundation, Inc.,
-+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+
-+ The full GNU General Public License is included in this distribution in
-+ the file called "COPYING".
-+
-+ Contact Information::w
-+ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-+
-+*******************************************************************************/
-+#include "stmmac.h"
-+#include "dwmac1000.h"
-+#include <linux/export.h>
-+#include <linux/net_tstamp.h>
-+
-+/* PPSCMD0 */
-+#define STMMAC_PPSCMD_NONE 0x00 /* No command */
-+#define STMMAC_PPSCMD_START_SINGLE 0x01 /* Start single pulse */
-+#define STMMAC_PPSCMD_START_PULSE 0x02 /* Start pulse train */
-+#define STMMAC_PPSCMD_START_CANCEL 0x03 /* Cancel start */
-+#define STMMAC_PPSCMD_STOP_PULSE_ATTIME 0x04 /* Stop pulse train at time */
-+#define STMMAC_PPSCMD_STOP_PULSE_IMMED 0x05 /* Stop pulse train immediate */
-+#define STMMAC_PPSCMD_STOP_CANCEL 0x06 /* Stop cancel pulse train */
-+
-+#define STMMAC_PTP_OVERFLOW_CHECK_ENABLED (u32)(1)
-+#define STMMAC_PTP_PPS_ENABLED (u32)(1 << 1)
-+#define STMMAC_PTP_HWTS_TX_EN (u32)(1 << 2)
-+#define STMMAC_PTP_HWTS_RX_EN (u32)(1 << 3)
-+
-+#ifndef NSECS_PER_SEC
-+#define NSECS_PER_SEC 1000000000ULL
-+#endif
-+
-+/*
-+ * Structure of STMMAC timer registers
-+ *
-+ * GMAC_TS_HWSEC GMAC_ST_SEC GMAC_ST_NSEC
-+ * +--------------+ +--------------+ +---+---+------+
-+ * STMMAC | 16 | | 32 | | 32 |
-+ * +--------------+ +--------------+ +---+---+------+
-+ *
-+ * The counter for the STMMAC is 80 bits
-+ * - HWSEC == overflow value for ST_SEC => 130 years to overflow (optional)
-+ * - ST_SEC == seconds
-+ * - ST_NSEC == nanoseconds
-+ */
-+
-+/**
-+ * stmmac_ptp_read - read raw cycle counter (to be used by time counter)
-+ * @cc - the cyclecounter structure
-+ *
-+ * this function reads the cyclecounter registers and is called by the
-+ * cyclecounter structure used to construct a ns counter from the
-+ * arbitrary fixed point registers
-+ */
-+static cycle_t stmmac_ptp_read(const struct cyclecounter *ccnt)
-+{
-+ struct stmmac_priv *priv =
-+ container_of(ccnt, struct stmmac_priv, ccnt);
-+ cycle_t stamp = 0;
-+
-+ stamp = (u64)readl(priv->ioaddr + GMAC_ST_NSEC);
-+ stamp |= (u64)readl(priv->ioaddr + GMAC_ST_SEC) << 32;
-+
-+ return stamp;
-+}
-+
-+/**
-+ * stmmac_ptp_adjfreq
-+ * @ptp - the ptp clock structure
-+ * @ppb - parts per billion adjustment from base
-+ *
-+ * adjust the frequency of the ptp cycle counter by the
-+ * indicated ppb from the base frequency.
-+ */
-+static int stmmac_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
-+{
-+ return 0;
-+}
-+
-+/**
-+ * stmmac_ptp_adjtime
-+ * @ptp - the ptp clock structure
-+ * @delta - offset to adjust the cycle counter by
-+ *
-+ * adjust the timer by resetting the timecounter structure.
-+ */
-+static int stmmac_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
-+{
-+ struct stmmac_priv *priv =
-+ container_of(ptp, struct stmmac_priv, ptp_caps);
-+ unsigned long flags;
-+ u64 now;
-+
-+ spin_lock_irqsave(&priv->tmreg_lock, flags);
-+
-+ now = timecounter_read(&priv->tcnt);
-+ now += delta;
-+
-+ /* reset the timecounter */
-+ timecounter_init(&priv->tcnt,
-+ &priv->ccnt,
-+ now);
-+
-+ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
-+ return 0;
-+}
-+
-+/**
-+ * stmmac_ptp_gettime
-+ * @ptp - the ptp clock structure
-+ * @ts - timespec structure to hold the current time value
-+ *
-+ * read the timecounter and return the correct value on ns,
-+ * after converting it into a struct timespec.
-+ */
-+static int stmmac_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
-+{
-+ struct stmmac_priv *priv =
-+ container_of(ptp, struct stmmac_priv, ptp_caps);
-+ u64 ns;
-+ u32 remainder;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&priv->tmreg_lock, flags);
-+ ns = timecounter_read(&priv->tcnt);
-+ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
-+
-+ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
-+ ts->tv_nsec = remainder;
-+
-+ return 0;
-+}
-+
-+/**
-+ * stmmac_ptp_settime
-+ * @ptp - the ptp clock structure
-+ * @ts - the timespec containing the new time for the cycle counter
-+ *
-+ * reset the timecounter to use a new base value instead of the kernel
-+ * wall timer value.
-+ */
-+static int stmmac_ptp_settime(struct ptp_clock_info *ptp,
-+ const struct timespec *ts)
-+{
-+ struct stmmac_priv *priv =
-+ container_of(ptp, struct stmmac_priv, ptp_caps);
-+ u64 ns;
-+ unsigned long flags;
-+
-+ ns = ts->tv_sec * 1000000000ULL;
-+ ns += ts->tv_nsec;
-+
-+ /* reset the timecounter */
-+ spin_lock_irqsave(&priv->tmreg_lock, flags);
-+ timecounter_init(&priv->tcnt, &priv->ccnt, ns);
-+ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
-+
-+ return 0;
-+}
-+
-+/**
-+ * stmmac_ptp_enable
-+ * @ptp - the ptp clock structure
-+ * @rq - the requested feature to change
-+ * @on - whether to enable or disable the feature
-+ *
-+ * enable (or disable) ancillary features of the phc subsystem.
-+ * our driver only supports the PPS feature on the X540
-+ */
-+static int stmmac_ptp_enable(struct ptp_clock_info *ptp,
-+ struct ptp_clock_request *rq, int on)
-+{
-+ struct stmmac_priv *priv =
-+ container_of(ptp, struct stmmac_priv, ptp_caps);
-+ uint32_t reg = 0;
-+
-+ /**
-+ * When enabling PPS functionality in STMMAC we need to unmask the
-+ * interrupt mask reg and enable the TSTRIG bit in the timestamp control
-+ * reg
-+ */
-+ if (rq->type == PTP_CLK_REQ_PPS) {
-+ if (on){
-+ priv->hwts |= STMMAC_PTP_PPS_ENABLED;
-+
-+ /* Enable TSTRIG */
-+ reg = readl(priv->ioaddr + GMAC_TS_CTRL);
-+ reg |= GMAC_TS_CTRL_TSTRIG;
-+ writel(reg, priv->ioaddr + GMAC_TS_CTRL);
-+ wmb();
-+
-+ /* Unmask interrupt */
-+ reg = readl(priv->ioaddr + GMAC_INT_MASK);
-+ printk(KERN_INFO "%s[on] read interrupt mask 0x%08x\n", __func__, reg);
-+ reg &= ~GMAC_INT_MASK_TSIM;
-+ printk(KERN_INFO "%s[on] write interrupt mask 0x%08x\n", __func__, reg);
-+ writel(reg, priv->ioaddr + GMAC_INT_MASK);
-+ wmb();
-+
-+ } else {
-+ /* Mask interrupt */
-+ reg = readl(priv->ioaddr + GMAC_INT_MASK);
-+ printk(KERN_INFO "%s[off] read interrupt mask 0x%08x\n", __func__, reg);
-+ reg |= GMAC_INT_MASK_TSIM;
-+ printk(KERN_INFO "%s[off] write interrupt mask 0x%08x\n", __func__, reg);
-+ writel(reg, priv->ioaddr + GMAC_INT_MASK);
-+ wmb();
-+
-+ /* Disable TSTRIG */
-+ reg = readl(priv->ioaddr + GMAC_TS_CTRL);
-+ reg &= ~GMAC_TS_CTRL_TSTRIG;
-+ writel(reg, priv->ioaddr + GMAC_TS_CTRL);
-+ wmb();
-+
-+ priv->hwts &=
-+ ~STMMAC_PTP_PPS_ENABLED;
-+ }
-+ return 0;
-+ }
-+
-+ return -ENOTSUPP;
-+}
-+
-+/**
-+ * stmmac_ptp_check_pps_event
-+ * @priv - the private priv structure
-+ *
-+ * This function is called by the interrupt routine when checking for
-+ * interrupts. It will check and handle a pps event.
-+ */
-+void stmmac_ptp_check_pps_event(struct stmmac_priv *priv)
-+{
-+ struct ptp_clock_event event;
-+ event.type = PTP_CLOCK_PPS;
-+
-+ /* Make sure ptp clock is valid, and PPS event enabled */
-+ if (!priv->ptp_clock ||
-+ !(priv->hwts & STMMAC_PTP_PPS_ENABLED)){
-+ return;
-+ }
-+
-+ ptp_clock_event(priv->ptp_clock, &event);
-+}
-+
-+#if 0
-+/**
-+ * stmmac_ptp_overflow_check - delayed work to detect SYSTIME overflow
-+ * @work: structure containing information about this work task
-+ *
-+ * this work function is scheduled to continue reading the timecounter
-+ * in order to prevent missing when the system time registers wrap
-+ * around. This needs to be run approximately twice a minute when no
-+ * PTP activity is occurring.
-+ */
-+void stmmac_ptp_overflow_check(struct stmmac_priv *priv)
-+{
-+ unsigned long elapsed_jiffies = priv->last_overflow_check - jiffies;
-+ struct timespec ts;
-+
-+ if ((priv->hwts & STMMAC_PTP_OVERFLOW_CHECK_ENABLED) &&
-+ (elapsed_jiffies >= STMMAC_OVERFLOW_PERIOD)) {
-+ stmmac_ptp_gettime(&priv->ptp_caps, &ts);
-+ priv->last_overflow_check = jiffies;
-+ }
-+}
-+#endif
-+
-+/**
-+ * stmmac_ptp_tx_hwtstamp - utility function which checks for TX time stamp
-+ * @q_vector: structure containing interrupt and ring information
-+ * @skb: particular skb to send timestamp with
-+ *
-+ * if the timestamp is valid, we convert it into the timecounter ns
-+ * value, then store that result into the shhwtstamps structure which
-+ * is passed up the network stack
-+ */
-+void stmmac_ptp_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
-+ struct sk_buff *skb)
-+{
-+ /* Sanity check input */
-+ if (unlikely(priv == NULL || pdma == NULL || skb == NULL)){
-+ return;
-+ }
-+
-+ if(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP){
-+ struct skb_shared_hwtstamps shhwtstamps;
-+ u64 ns;
-+ u64 regval;
-+ unsigned long flags;
-+
-+ regval = (u64)pdma->ts_lo;
-+ regval |= (u64)pdma->ts_hi << 32;
-+
-+ spin_lock_irqsave(&priv->tmreg_lock, flags);
-+ ns = timecounter_cyc2time(&priv->tcnt, regval);
-+ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
-+
-+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-+ shhwtstamps.hwtstamp = ns_to_ktime(ns);
-+ skb_tstamp_tx(skb, &shhwtstamps);
-+ }
-+}
-+
-+/**
-+ * stmmac_ptp_rx_hwtstamp - utility function which checks for RX time stamp
-+ * @q_vector: structure containing interrupt and ring information
-+ * @skb: particular skb to send timestamp with
-+ *
-+ * if the timestamp is valid, we convert it into the timecounter ns
-+ * value, then store that result into the shhwtstamps structure which
-+ * is passed up the network stack
-+ */
-+void stmmac_ptp_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
-+ struct sk_buff *skb)
-+{
-+ /* Sanity check input */
-+ if (unlikely(priv == NULL || pdma == NULL || skb == NULL)){
-+ return;
-+ }
-+
-+ if(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP){
-+ struct skb_shared_hwtstamps shhwtstamps;
-+ u64 ns;
-+ u64 regval;
-+ unsigned long flags;
-+
-+ regval = (u64)pdma->ts_lo;
-+ regval |= (u64)pdma->ts_hi << 32;
-+
-+ spin_lock_irqsave(&priv->tmreg_lock, flags);
-+ ns = timecounter_cyc2time(&priv->tcnt, regval);
-+ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
-+
-+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-+ shhwtstamps.hwtstamp = ns_to_ktime(ns);
-+ }
-+}
-+
-+/**
-+ * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping
-+ * @priv: pointer to priv struct
-+ * @ifreq: ioctl data
-+ * @cmd: particular ioctl requested
-+ *
-+ * Outgoing time stamping can be enabled and disabled. Play nice and
-+ * disable it when requested, although it shouldn't case any overhead
-+ * when no packet needs it. At most one packet in the queue may be
-+ * marked for time stamping, otherwise it would be impossible to tell
-+ * for sure to which packet the hardware time stamp belongs.
-+ *
-+ * Incoming time stamping has to be configured via the hardware
-+ * filters. Not all combinations are supported, in particular event
-+ * type has to be specified. Matching the kind of event packet is
-+ * not supported, with the exception of "all V2 events regardless of
-+ * level 2 or 4".
-+ */
-+int stmmac_ptp_hwtstamp_ioctl(struct stmmac_priv *priv,
-+ struct ifreq *ifr, int cmd)
-+{
-+ struct hwtstamp_config config;
-+// struct stmmac_priv *priv = netdev_priv(netdev);
-+ u32 tsctl = 0;
-+
-+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
-+ return -EFAULT;
-+
-+ /* reserved for future extensions */
-+ if (config.flags)
-+ return -EINVAL;
-+
-+ /* Snapshot the reg - preserve Timestamp Interrupt Trigger Enable */
-+ tsctl = readl(priv->ioaddr + GMAC_TS_CTRL) & GMAC_TS_CTRL_TSTRIG;
-+
-+ /* TX */
-+ switch (config.tx_type) {
-+ case HWTSTAMP_TX_OFF:
-+ priv->hwts &= ~STMMAC_PTP_HWTS_TX_EN;
-+ printk(KERN_INFO "%s set TX PTP en false\n", __func__);
-+ break;
-+ case HWTSTAMP_TX_ON:
-+ priv->hwts |= STMMAC_PTP_HWTS_TX_EN;
-+ printk(KERN_INFO "%s set TX PTP en true\n", __func__);
-+ break;
-+ default:
-+ return -ERANGE;
-+ }
-+
-+ /* RX */
-+ priv->hwts |= STMMAC_PTP_HWTS_RX_EN;
-+
-+ switch (config.rx_filter) {
-+
-+
-+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
-+ /*
-+ * V1_L4 UDP any event
-+ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
-+ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
-+ *
-+ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=0, IPV4=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_EVENT \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-+ /*
-+ * V1_L4 Master
-+ * Delay_Req
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=0, IPV4=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
-+ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-+ /*
-+ * V1_L4 Slave
-+ * Sync
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=0, IPV4=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSEVNTENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_SYNC \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
-+ /*
-+ * V2_L4 UDP any event
-+ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
-+ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
-+ *
-+ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1, IPV4=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_EVENT \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
-+ /*
-+ * V2_L4 Master
-+ * Delay_Req
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=1, IPV4=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
-+ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
-+
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
-+ /*
-+ * V2_L4 Slave
-+ * Sync
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1, IPV4=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSEVNTENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_SYNC \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
-+ /*
-+ * V2_L2 Ethernet any event
-+ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
-+ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
-+ *
-+ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1,TSIPENA=1
-+ * TSIPENA=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSIPENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_EVENT \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
-+ /*
-+ * V2_L2 Master
-+ * Delay_Req
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=1,TSIPENA=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
-+ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
-+ /*
-+ * V2_L2 Slave
-+ * Sync
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1,
-+ * TSIPENA=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA;
-+ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_SYNC \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
-+ /*
-+ * V2_L2 Ethernet any event
-+ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
-+ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
-+ *
-+ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1
-+ * TSIPENA=1, TSIPV4ENA=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPENA | GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_EVENT \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
-+ /*
-+ * V2_L2_L4 Master
-+ * Delay_Req
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1,
-+ * TSVER2ENA=1,TSIPENA=1, TSIPV4ENA=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
-+ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPENA | GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_DELAY_REQ \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
-+ /*
-+ * V2_L2_L4 Slave
-+ * Sync
-+ *
-+ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1,
-+ * TSIPENA=1, TSIPV4ENA=1
-+ */
-+ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA;
-+ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPENA;
-+ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_SYNC \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_ALL:
-+ /*
-+ * V2_L2_L4 Ethernet any event
-+ *
-+ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
-+ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
-+ *
-+ * GMAC_TS_CTRL_TSENALL
-+ */
-+ tsctl |= GMAC_TS_CTRL_TSENALL;
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_ALL \n", __func__);
-+ break;
-+
-+ case HWTSTAMP_FILTER_NONE:
-+ printk(KERN_INFO "%s HWTSTAMP_FILTER_NONE \n", __func__);
-+ priv->hwts &= ~STMMAC_PTP_HWTS_RX_EN;
-+ break;
-+
-+ default:
-+ printk(KERN_INFO "%s error ioctl rx type %d \n", __func__, config.rx_filter);
-+ /* bad/unknown parameter */
-+ return -ERANGE;
-+ }
-+
-+ /* Set the TS CTRL reg */
-+ tsctl |= GMAC_TS_CTRL_TSENA;
-+ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
-+ wmb();
-+
-+ printk(KERN_INFO "%s sync ts_ctl @ value 0x%08x\n", __func__, tsctl);
-+
-+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-+ -EFAULT : 0;
-+}
-+
-+
-+#define DEFAULT_PTP_CLK 50
-+
-+/**
-+ * stmmac_ptp_init_timestamp - initialise the PTP clock
-+ * @priv - pointer to the priv structure
-+ *
-+ * This function initialises the PTP clock consistent with the method spelled
-+ * out in the Snopsys documentation
-+ */
-+static void stmmac_ptp_init_timestamp(struct stmmac_priv *priv)
-+{
-+ unsigned long tsctl = GMAC_TS_CTRL_TSENA, flags = 0;
-+ uint8_t ssinc = CONFIG_STMMAC_PTP_CLK_MHZ;
-+
-+ /* Enable TS */
-+ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
-+ wmb();
-+
-+ /* Write SSINC - number of nano seconds to increment on each clock */
-+ if(ssinc == 0){
-+ ssinc = DEFAULT_PTP_CLK;
-+ }
-+ ssinc = 1000/ssinc;
-+ writel(ssinc, priv->ioaddr + GMAC_SS_INC);
-+ wmb();
-+
-+ printk(KERN_INFO "%s setting PTP_CLK to 0x%02x\n", __func__, ssinc);
-+
-+ /* Reset system time registers to zero */
-+ writel(0x00000000, priv->ioaddr + GMAC_ST_SEC);
-+ writel(0x00000000, priv->ioaddr + GMAC_ST_NSEC);
-+ wmb();
-+
-+ /* Set TSINT to latch values in ST_SEC and ST_NSEC */
-+ tsctl |= GMAC_TS_CTRL_TSINT;
-+ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
-+ wmb();
-+ printk(KERN_INFO "%s tsctl == 0x%08lx (TSINIT | TSENA)\n", __func__, tsctl);
-+
-+ spin_lock_irqsave(&priv->tmreg_lock, flags);
-+
-+ /* Init timecounter */
-+ memset(&priv->ccnt, 0, sizeof(priv->ccnt));
-+ priv->ccnt.read = stmmac_ptp_read;
-+ priv->ccnt.mask = CLOCKSOURCE_MASK(64);
-+ priv->ccnt.mult = 1;
-+ priv->ccnt.shift = 0;
-+
-+ /* reset the ns time counter */
-+ timecounter_init(&priv->tcnt, &priv->ccnt,
-+ ktime_to_ns(ktime_get_real()));
-+
-+ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
-+}
-+
-+/**
-+ * stmmac_ptp_init
-+ * @priv - the stmmac private priv structure
-+ *
-+ * This function performs the required steps for enabling ptp
-+ * support. If ptp support has already been loaded it simply calls the
-+ * cyclecounter init routine and exits.
-+ */
-+void stmmac_ptp_init(struct net_device *ndev, struct device * pdev)
-+{
-+ struct stmmac_priv *priv = netdev_priv(ndev);
-+
-+ /* Ensure the timestamp interrupt is masked */
-+ writel(GMAC_INT_MASK_TSIM, priv->ioaddr + GMAC_INT_MASK);
-+
-+ /* Fill out PTP callback contents */
-+ snprintf(priv->ptp_caps.name, 16, "%pm", ndev->dev_addr);
-+ priv->ptp_caps.owner = THIS_MODULE;
-+ priv->ptp_caps.max_adj = 0; /* Cannot be adjusted */
-+ priv->ptp_caps.n_alarm = 0;
-+ priv->ptp_caps.n_ext_ts = 0;
-+ priv->ptp_caps.n_per_out = 0;
-+ priv->ptp_caps.pps = 0;
-+ priv->ptp_caps.adjfreq = stmmac_ptp_adjfreq;
-+ priv->ptp_caps.adjtime = stmmac_ptp_adjtime;
-+ priv->ptp_caps.gettime = stmmac_ptp_gettime;
-+ priv->ptp_caps.settime = stmmac_ptp_settime;
-+ priv->ptp_caps.enable = stmmac_ptp_enable;
-+
-+ spin_lock_init(&priv->tmreg_lock);
-+
-+ stmmac_ptp_init_timestamp(priv);
-+
-+ /* Init to default state */
-+// priv->hwts = STMMAC_PTP_OVERFLOW_CHECK_ENABLED;
-+
-+ priv->ptp_clock = ptp_clock_register(&priv->ptp_caps, pdev);
-+ if (IS_ERR(priv->ptp_clock)) {
-+ priv->ptp_clock = NULL;
-+ printk(KERN_ERR "%s ptp_clock_reg failed!\n", __func__);
-+ } else {
-+ printk(KERN_INFO "%s ptp_clock_reg success!\n", __func__);
-+ }
-+
-+ return;
-+}
-+
-+/**
-+ * stmmac_ptp_remove - disable ptp device and stop the overflow check
-+ * @priv: pointer to priv struct
-+ *
-+ * this function stops the ptp support, and cancels the delayed work.
-+ */
-+void stmmac_ptp_remove(struct stmmac_priv *priv)
-+{
-+ /* Ensure the timestamp interrupt is masked */
-+ writel(GMAC_INT_MASK_TSIM, priv->ioaddr + GMAC_INT_MASK);
-+
-+ /* stop the overflow check task */
-+// priv->hwts &= ~STMMAC_PTP_OVERFLOW_CHECK_ENABLED;
-+
-+ if (priv->ptp_clock != NULL) {
-+ ptp_clock_unregister(priv->ptp_clock);
-+ priv->ptp_clock = NULL;
-+ printk(KERN_INFO "%s removed ptp_clock\n", __func__);
-+ }
-+}
-+
-diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
-index 044b532..dc92097 100644
---- a/drivers/net/phy/mdio_bus.c
-+++ b/drivers/net/phy/mdio_bus.c
-@@ -95,7 +95,7 @@ static struct class mdio_bus_class = {
-
- #if IS_ENABLED(CONFIG_OF_MDIO)
- /* Helper function for of_mdio_find_bus */
--static int of_mdio_bus_match(struct device *dev, void *mdio_bus_np)
-+static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np)
- {
- return dev->of_node == mdio_bus_np;
- }
-diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
-index c86bae8..6def5f6 100644
---- a/drivers/platform/x86/Kconfig
-+++ b/drivers/platform/x86/Kconfig
-@@ -672,6 +672,10 @@ config INTEL_MFLD_THERMAL
- Say Y here to enable thermal driver support for the Intel Medfield
- platform.
-
-+if INTEL_QUARK_X1000_SOC
-+source "drivers/platform/x86/quark/Kconfig"
-+endif
-+
- config INTEL_IPS
- tristate "Intel Intelligent Power Sharing"
- depends on ACPI
-diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
-index bf7e4f9..fce76ef 100644
---- a/drivers/platform/x86/Makefile
-+++ b/drivers/platform/x86/Makefile
-@@ -50,3 +50,4 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
- obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
- obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
- obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += quark/
-diff --git a/drivers/platform/x86/quark/Kconfig b/drivers/platform/x86/quark/Kconfig
-new file mode 100644
-index 0000000..dffa0fc
---- /dev/null
-+++ b/drivers/platform/x86/quark/Kconfig
-@@ -0,0 +1,41 @@
-+config INTEL_CLN_ESRAM
-+ bool "eSRAM - embedded SRAM driver for Intel Clanton platform"
-+ depends on INTEL_QUARK_X1000_SOC && PM
-+ select KALLSYMS
-+ select CRC16
-+ help
-+ Say Y here to enable eSRAM overlay and software-initiated ECC
-+ updates. eSRAM overlaying allows for code/data structures to be
-+ mapped into eSRAM thus providing far faster access to code/data
-+ than ordinary DRAM. Slower than cache RAM faster than DRAM.
-+
-+config INTEL_CLN_ECC_REFRESH_PERIOD
-+ int "Choose eSRAM ECC coverage period"
-+ depends on INTEL_CLN_ESRAM
-+ default 24
-+ help
-+ Select the period over which *RAM ECC codes should be refreshed.
-+ IA Core will periodically enable disabled eSRAM pages to ensure all of
-+ disabled eSRAM pages are 'address walked' in this period. A logical
-+ component within the silicon on Clanton will ensure DRAM (and
-+ overlayed eSRAM) pages by extension are similarly updated over the
-+ same period. This variable controlls how long a time this address
-+ walking algorithm should take. For a noisy environment like a
-+ sub-station or a satellite update frequently. For less noisy
-+ environments this value should be lower. Default 24 hours is right for
-+ most people. Set to zero to disable - this is NOT recommended. Max 48
-+ hours.
-+
-+config INTEL_CLN_THERMAL
-+ bool "Thermal driver for Intel Clanton platform"
-+ depends on INTEL_QUARK_X1000_SOC
-+ help
-+ Say Y here to enable Clanton's Thermal driver plus the MSI's
-+ that can be hooked from the thermal sub-system
-+
-+config INTEL_CLN_AUDIO_CTRL
-+ tristate "Audio sub-system control driver for Intel Clanton platform"
-+ depends on INTEL_QUARK_X1000_SOC
-+ help
-+ Say Y here to enable Clanton's audio control driver
-+
-diff --git a/drivers/platform/x86/quark/Makefile b/drivers/platform/x86/quark/Makefile
-new file mode 100644
-index 0000000..53bfc65
---- /dev/null
-+++ b/drivers/platform/x86/quark/Makefile
-@@ -0,0 +1,15 @@
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_board_data.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_clanton_hill.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_clanton_peak.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_cross_hill.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_kips_bay.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_galileo.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_sb.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_imr.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_imr_kernel.o
-+obj-$(CONFIG_INTEL_CLN_ESRAM) += intel_cln_esram.o
-+obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_imr_test.o
-+obj-$(CONFIG_INTEL_CLN_ESRAM) += intel_cln_esram_test.o
-+#obj-$(CONFIG_INTEL_CLN_ESRAM) += intel_cln_smep_test.o
-+obj-$(CONFIG_INTEL_CLN_THERMAL) += intel_cln_thermal.o
-+obj-$(CONFIG_INTEL_CLN_AUDIO_CTRL) += intel_cln_audio_ctrl.o
-diff --git a/drivers/platform/x86/quark/intel_cln_audio_ctrl.c b/drivers/platform/x86/quark/intel_cln_audio_ctrl.c
-new file mode 100644
-index 0000000..95bfe78
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_audio_ctrl.c
-@@ -0,0 +1,514 @@
-+/*
-+ * Intel Clanton platform audio control driver
-+ *
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ *
-+ * The Intel Clanton Hill platform hardware design includes an audio subsystem
-+ * with a number of interconnected audio interfaces. This driver enables
-+ * applications to choose which audio connections to enable for various
-+ * application use cases. The interconnections are selectable using GPIO output
-+ * pins on the CPU. This driver is also responsible for configuring a Maxim
-+ * 9867 audio codec, a component of this audio subsystem, connected to the CPU
-+ * via I2C.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/printk.h>
-+#include <linux/platform_device.h>
-+#include <linux/types.h>
-+#include <linux/err.h>
-+#include <linux/i2c.h>
-+#include <linux/gpio.h>
-+#include <linux/cdev.h>
-+#include <linux/fs.h>
-+#include <uapi/linux/ioctl.h>
-+#include <linux/mutex.h>
-+#include <linux/sysfs.h>
-+
-+#include "intel_cln_audio_ctrl.h"
-+
-+#define DRIVER_NAME "intel_cln_audio_ctrl"
-+
-+/*
-+ * GPIO numbers to use for switching audio paths
-+ */
-+#define GPIO_AUDIO_S0 11
-+#define GPIO_AUDIO_S1 12
-+#define GPIO_AUDIO_S2 13
-+
-+#define GPIO_AUDIO_DEFAULT (INTEL_CLN_AUDIO_MODE_SPKR_MIC)
-+
-+/**
-+ * struct intel_cln_audio_ctrl_data
-+ *
-+ * Structure to represent module state/data/etc
-+ */
-+struct intel_cln_audio_ctrl_priv {
-+
-+ /* i2c device descriptor for read/write access to MAX9867 registers */
-+ struct i2c_client *max9867_i2c;
-+
-+ /* Char dev to provide user-space ioctl interface for audio control */
-+ struct cdev cdev;
-+ dev_t cdev_no;
-+ struct class *cl;
-+
-+ /* Mutex to protect against concurrent access to the ioctl() handler */
-+ struct mutex lock;
-+
-+ /* Current GPIO switch value */
-+ unsigned char gpio_val;
-+};
-+
-+static int
-+intel_cln_audio_ctrl_open(struct inode *inode, struct file *filp)
-+{
-+ struct intel_cln_audio_ctrl_priv *priv;
-+
-+ priv = container_of(inode->i_cdev,
-+ struct intel_cln_audio_ctrl_priv,
-+ cdev);
-+ filp->private_data = priv;
-+
-+ return 0;
-+}
-+
-+static int
-+intel_cln_audio_ctrl_release(struct inode *inode, struct file *filp)
-+{
-+ return 0;
-+}
-+
-+/*
-+ * Logic truth table for AUDIO_S[0-3] outputs, illustrating which paths are
-+ * connected between audio interfaces A, B, C. Each audio interface has one
-+ * effective input (I) port and one effective output (O) port
-+ *
-+ * A = USB Codec (to Clanton CPU)
-+ * B = Spkr/Mic (to car audio system)
-+ * C = I2S Codec (to Telit HE910)
-+ *
-+ * PATH examples:
-+ * AO-CO: A-Output connected to C-Output
-+ * BI-AI: B-Input connected to A-Input
-+ *
-+ * NOTE: Assume a CI-AI connection is available in ALL cases (sometimes unused)
-+ *
-+ * S2 S1 S0 PATHS USE CASE
-+ * -- -- -- ----------------- -------------------------------------------------
-+ * 0 0 0 AO-CO BT Headset call
-+ * 0 0 1 AO-BO Analog Driver Alerts (CI unused)
-+ * 0 1 0 AO-CO,BI-AI XX Unused/invalid (BI *and* CI connected to AI)
-+ * 0 1 1 AO-BO,BI-AI Archival Voice Record/Playback (or Driver Alerts)
-+ * 1 0 0 AO-CO,BI-CO XX Unused/invalid (A0 *and* BI connected to CO)
-+ * 1 0 1 AO-BO,BI-CO Analog hands-free call
-+ * 1 1 0 AO-CO,BI-AI,BI-CO XX Unused/invalid (BI connected to AI *and* CO)
-+ * 1 1 1 AO-BO,BI-AI,BI-CO XX Unused/invalid (BI connected to AI *and* CO)
-+ *
-+ *
-+ * Mapping to IOCTLs (using more intuitive naming on the API):
-+ *
-+ * PATHS IOCTL
-+ * --------------- -------------------------------------------------------------
-+ * AO-CO INTEL_CLN_AUDIO_MODE_GSM_ONLY
-+ * AO-BO INTEL_CLN_AUDIO_MODE_SPKR_ONLY
-+ * AO-BO,BI-AI INTEL_CLN_AUDIO_MODE_SPKR_MIC
-+ * AO-BO,BI-CO INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC
-+ */
-+
-+static int
-+intel_cln_audio_ctrl_gpio_update(struct intel_cln_audio_ctrl_priv *priv)
-+{
-+ int ret = 0;
-+ struct gpio audio_sw_gpios[] = {
-+ {
-+ GPIO_AUDIO_S2,
-+ GPIOF_OUT_INIT_LOW,
-+ "audio_s2"
-+ },
-+ {
-+ GPIO_AUDIO_S1,
-+ GPIOF_OUT_INIT_LOW,
-+ "audio_s1"
-+ },
-+ {
-+ GPIO_AUDIO_S0,
-+ GPIOF_OUT_INIT_LOW,
-+ "audio_s0"
-+ }
-+ };
-+
-+ /*
-+ * Update the Audio Switch GPIO outputs according to the user selection
-+ */
-+ ret = gpio_request_array(audio_sw_gpios,
-+ ARRAY_SIZE(audio_sw_gpios));
-+ if (ret) {
-+ pr_err("%s: Failed to allocate audio control GPIO pins\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ gpio_set_value(GPIO_AUDIO_S2, (priv->gpio_val >> 2) & 0x1);
-+ gpio_set_value(GPIO_AUDIO_S1, (priv->gpio_val >> 1) & 0x1);
-+ gpio_set_value(GPIO_AUDIO_S0, (priv->gpio_val >> 0) & 0x1);
-+
-+ gpio_free_array(audio_sw_gpios,
-+ ARRAY_SIZE(audio_sw_gpios));
-+
-+ return 0;
-+}
-+
-+static long
-+intel_cln_audio_ctrl_ioctl(struct file *filp,
-+ unsigned int cmd,
-+ unsigned long arg)
-+{
-+ struct intel_cln_audio_ctrl_priv *priv = filp->private_data;
-+ int ret = 0;
-+
-+ ret = mutex_lock_interruptible(&priv->lock);
-+ if (ret)
-+ return ret;
-+
-+ switch (cmd) {
-+ case INTEL_CLN_AUDIO_MODE_IOC_GSM_ONLY:
-+ case INTEL_CLN_AUDIO_MODE_IOC_SPKR_ONLY:
-+ case INTEL_CLN_AUDIO_MODE_IOC_SPKR_MIC:
-+ case INTEL_CLN_AUDIO_MODE_IOC_GSM_SPKR_MIC:
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto exit;
-+ }
-+
-+ priv->gpio_val = _IOC_NR(cmd) & 0x7;
-+ ret = intel_cln_audio_ctrl_gpio_update(priv);
-+exit:
-+ mutex_unlock(&priv->lock);
-+ return ret;
-+}
-+
-+static const struct file_operations intel_cln_audio_ctrl_fops = {
-+ .owner = THIS_MODULE,
-+ .open = intel_cln_audio_ctrl_open,
-+ .release = intel_cln_audio_ctrl_release,
-+ .unlocked_ioctl = intel_cln_audio_ctrl_ioctl
-+};
-+
-+static int
-+intel_cln_audio_ctrl_chrdev_init(struct intel_cln_audio_ctrl_priv *priv)
-+{
-+ /* Register a character dev interface (with ioctls)
-+ * to allow control of the audio subsystem switch
-+ */
-+ int ret;
-+ struct device *dev;
-+
-+ ret = alloc_chrdev_region(&priv->cdev_no, 0, 1,
-+ "intel_cln_audio_ctrl");
-+ if (ret) {
-+ pr_err("Failed to alloc chrdev: %d", ret);
-+ return ret;
-+ }
-+
-+ cdev_init(&priv->cdev, &intel_cln_audio_ctrl_fops);
-+
-+ ret = cdev_add(&priv->cdev, priv->cdev_no, 1);
-+ if (ret) {
-+ pr_err("Failed to add cdev: %d", ret);
-+ unregister_chrdev_region(priv->cdev_no, 1);
-+ return ret;
-+ }
-+
-+ priv->cl = class_create(THIS_MODULE, "char");
-+ if (IS_ERR(priv->cl)) {
-+ pr_err("Failed to create device class: %ld",
-+ PTR_ERR(priv->cl));
-+ cdev_del(&priv->cdev);
-+ unregister_chrdev_region(priv->cdev_no, 1);
-+ return PTR_ERR(priv->cl);
-+ }
-+
-+ dev = device_create(priv->cl, NULL, priv->cdev_no, NULL,
-+ "intel_cln_audio_ctrl");
-+ if (IS_ERR(dev)) {
-+ pr_err("Failed to create device: %ld",
-+ PTR_ERR(priv->cl));
-+ class_destroy(priv->cl);
-+ cdev_del(&priv->cdev);
-+ unregister_chrdev_region(priv->cdev_no, 1);
-+ return PTR_ERR(dev);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+intel_cln_audio_ctrl_chrdev_remove(struct intel_cln_audio_ctrl_priv *priv)
-+{
-+ device_destroy(priv->cl, priv->cdev_no);
-+ class_destroy(priv->cl);
-+ cdev_del(&priv->cdev);
-+ unregister_chrdev_region(priv->cdev_no, 1);
-+
-+ return 0;
-+}
-+
-+
-+ssize_t intel_cln_audio_ctrl_sysfs_show_mode(struct device *dev,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct intel_cln_audio_ctrl_priv *priv = dev_get_drvdata(dev);
-+ int ret;
-+ char *mode;
-+
-+ ret = mutex_lock_interruptible(&priv->lock);
-+ if (ret)
-+ return ret;
-+
-+ switch (priv->gpio_val) {
-+ case INTEL_CLN_AUDIO_MODE_GSM_ONLY:
-+ mode = "gsm";
-+ break;
-+ case INTEL_CLN_AUDIO_MODE_SPKR_ONLY:
-+ mode = "spkr";
-+ break;
-+ case INTEL_CLN_AUDIO_MODE_SPKR_MIC:
-+ mode = "spkr_mic";
-+ break;
-+ case INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC:
-+ mode = "gsm_spkr_mic";
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ goto exit;
-+ }
-+
-+ ret = scnprintf(buf, PAGE_SIZE, "%s\n", mode);
-+
-+exit:
-+ mutex_unlock(&priv->lock);
-+ return ret;
-+}
-+
-+ssize_t intel_cln_audio_ctrl_sysfs_store_mode(struct device *dev,
-+ struct device_attribute *attr,
-+ const char *buf, size_t count)
-+{
-+ struct intel_cln_audio_ctrl_priv *priv = dev_get_drvdata(dev);
-+ char mode[16];
-+ unsigned char gpio_val;
-+ int ret = count;
-+
-+ sscanf(buf, "%15s", mode);
-+
-+ if (!strcmp(mode, "gsm"))
-+ gpio_val = INTEL_CLN_AUDIO_MODE_GSM_ONLY;
-+ else if (!strcmp(mode, "spkr"))
-+ gpio_val = INTEL_CLN_AUDIO_MODE_SPKR_ONLY;
-+ else if (!strcmp(mode, "spkr_mic"))
-+ gpio_val = INTEL_CLN_AUDIO_MODE_SPKR_MIC;
-+ else if (!strcmp(mode, "gsm_spkr_mic"))
-+ gpio_val = INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC;
-+ else
-+ return -EINVAL;
-+
-+ ret = mutex_lock_interruptible(&priv->lock);
-+ if (ret)
-+ return ret;
-+
-+ priv->gpio_val = gpio_val;
-+ ret = intel_cln_audio_ctrl_gpio_update(priv);
-+ if (ret)
-+ goto exit;
-+
-+ ret = count;
-+
-+exit:
-+ mutex_unlock(&priv->lock);
-+
-+ return ret;
-+}
-+
-+/* Sysfs attribute descriptor (for alternative user-space interface) */
-+static DEVICE_ATTR(audio_switch_mode, S_IWUSR | S_IRUGO,
-+ intel_cln_audio_ctrl_sysfs_show_mode,
-+ intel_cln_audio_ctrl_sysfs_store_mode);
-+
-+/******************************************************************************
-+ * Module hooks
-+ ******************************************************************************/
-+
-+static int
-+intel_cln_max9867_init(struct i2c_client *client)
-+{
-+ int ret;
-+
-+ /* MAX9867 register configuration, from Telit HE910 DVI app-note */
-+
-+ u8 reg_cfg_seq1[] = {
-+ 0x04, /* Starting register address, followed by data */
-+ 0x00, /* 0x04 Interrupt Enable */
-+ 0x10, /* 0x05 System Clock */
-+ 0x90, /* 0x06 Audio Clock High */
-+ 0x00, /* 0x07 Audio Clock Low */
-+ 0x10, /* 0x08 Interface 1a */
-+ 0x0A, /* 0x09 Interface 1d */
-+ 0x33, /* 0x0A Codec Filters */
-+ 0x00, /* 0x0B DAC Gain/Sidetone */
-+ 0x00, /* 0x0C DAC Level */
-+ 0x33, /* 0x0D ADC Level */
-+ 0x4C, /* 0x0E Left Line Input Level */
-+ 0x4C, /* 0x0F Right Line Input Level */
-+ 0x00, /* 0x10 Left Volume Control */
-+ 0x00, /* 0x11 Right Volume Control */
-+ 0x14, /* 0x12 Left Mic Gain */
-+ 0x14, /* 0x13 Right Mic Gain */
-+ /* Configuration */
-+ 0xA0, /* 0x14 Input */
-+ 0x00, /* 0x15 Microphone */
-+ 0x65 /* 0x16 Mode */
-+ };
-+
-+ u8 reg_cfg_seq2[] = {
-+ 0x17, /* Starting register address, followed by data */
-+ 0xEF /* 0x17 System Shutdown */
-+ };
-+
-+ ret = i2c_master_send(client,
-+ reg_cfg_seq1, sizeof(reg_cfg_seq1));
-+ if (ret != sizeof(reg_cfg_seq1)) {
-+ pr_err("Failed to write MAX9867 config registers (set 1/2)");
-+ return -EIO;
-+ }
-+
-+ ret = i2c_master_send(client,
-+ reg_cfg_seq2, sizeof(reg_cfg_seq2));
-+ if (ret != sizeof(reg_cfg_seq2)) {
-+ pr_err("Failed to write MAX9867 config registers (set 2/2)");
-+ return -EIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+intel_cln_max9867_get_chip_rev(struct i2c_client *client)
-+{
-+ struct i2c_msg msg[2];
-+ u8 data[2];
-+ int ret;
-+
-+ data[0] = 0xFF; /* Chip-revision register address = 0xFF */
-+ msg[0].addr = client->addr;
-+ msg[0].flags = 0;
-+ msg[0].buf = &data[0];
-+ msg[0].len = 1;
-+
-+ msg[1].addr = client->addr;
-+ msg[1].flags = I2C_M_RD;
-+ msg[1].buf = &data[1];
-+ msg[1].len = 1;
-+
-+ ret = i2c_transfer(client->adapter, &msg[0], 2);
-+ return (ret == 2) ? data[1] : -EIO;
-+}
-+
-+static int intel_cln_max9867_i2c_probe(struct i2c_client *client,
-+ const struct i2c_device_id *id)
-+{
-+ struct intel_cln_audio_ctrl_priv *priv;
-+ int ret;
-+
-+ priv = devm_kzalloc(&client->dev, sizeof(*priv),
-+ GFP_KERNEL);
-+ if (priv == NULL)
-+ return -ENOMEM;
-+
-+ i2c_set_clientdata(client, priv);
-+
-+ priv->max9867_i2c = client;
-+ mutex_init(&priv->lock);
-+
-+ ret = intel_cln_max9867_get_chip_rev(client);
-+ if (ret >= 0)
-+ pr_info("%s: Detected MAX9867 chip revision 0x%02X\n",
-+ __func__, ret);
-+ else {
-+ pr_err("%s: Failed to read MAX9867 chip revision\n", __func__);
-+ goto exit;
-+ }
-+
-+ ret = intel_cln_max9867_init(client);
-+ if (ret)
-+ goto exit;
-+
-+ priv->gpio_val = GPIO_AUDIO_DEFAULT;
-+ ret = intel_cln_audio_ctrl_gpio_update(priv);
-+ if (ret)
-+ goto exit;
-+
-+ /* Create a char dev interface, providing an ioctl config option */
-+ ret = intel_cln_audio_ctrl_chrdev_init(priv);
-+ if (ret)
-+ goto exit;
-+
-+ /* Also create a sysfs interface, providing a cmd line config option */
-+ ret = sysfs_create_file(&client->dev.kobj,
-+ &dev_attr_audio_switch_mode.attr);
-+
-+exit:
-+ return ret;
-+}
-+
-+static int intel_cln_max9867_i2c_remove(struct i2c_client *client)
-+{
-+ struct intel_cln_audio_ctrl_priv *priv = i2c_get_clientdata(client);
-+
-+ intel_cln_audio_ctrl_chrdev_remove(priv);
-+
-+ sysfs_remove_file(&client->dev.kobj, &dev_attr_audio_switch_mode.attr);
-+
-+ return 0;
-+}
-+
-+static const struct i2c_device_id intel_cln_max9867_i2c_id[] = {
-+ {"intel-cln-max9867", 0},
-+ {}
-+};
-+MODULE_DEVICE_TABLE(i2c, intel_cln_max9867_i2c_id);
-+
-+/* i2c codec control layer */
-+static struct i2c_driver intel_cln_audio_ctrl_i2c_driver = {
-+ .driver = {
-+ .name = "intel_cln_audio_ctrl",
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_max9867_i2c_probe,
-+ .remove = intel_cln_max9867_i2c_remove,
-+ .id_table = intel_cln_max9867_i2c_id,
-+};
-+
-+module_i2c_driver(intel_cln_audio_ctrl_i2c_driver);
-+
-+MODULE_AUTHOR("Dan O'Donovan <dan@emutex.com>");
-+MODULE_DESCRIPTION("Intel Clanton platform audio control driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/platform/x86/quark/intel_cln_audio_ctrl.h b/drivers/platform/x86/quark/intel_cln_audio_ctrl.h
-new file mode 100644
-index 0000000..b6c4692
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_audio_ctrl.h
-@@ -0,0 +1,45 @@
-+/*
-+ * Intel Clanton platform audio control driver
-+ *
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ *
-+ * See intel_cln_audio_ctrl.c for a detailed description
-+ *
-+ */
-+
-+#ifndef __INTEL_CLN_AUDIO_CTRL_H__
-+#define __INTEL_CLN_AUDIO_CTRL_H__
-+
-+#include <linux/module.h>
-+
-+#define INTEL_CLN_AUDIO_MODE_GSM_ONLY 0x0
-+#define INTEL_CLN_AUDIO_MODE_SPKR_ONLY 0x1
-+#define INTEL_CLN_AUDIO_MODE_SPKR_MIC 0x3
-+#define INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC 0x5
-+
-+#define INTEL_CLN_AUDIO_MODE_IOC_GSM_ONLY \
-+ _IO('x', INTEL_CLN_AUDIO_MODE_GSM_ONLY)
-+#define INTEL_CLN_AUDIO_MODE_IOC_SPKR_ONLY \
-+ _IO('x', INTEL_CLN_AUDIO_MODE_SPKR_ONLY)
-+#define INTEL_CLN_AUDIO_MODE_IOC_SPKR_MIC \
-+ _IO('x', INTEL_CLN_AUDIO_MODE_SPKR_MIC)
-+#define INTEL_CLN_AUDIO_MODE_IOC_GSM_SPKR_MIC \
-+ _IO('x', INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC)
-+
-+#endif /* __INTEL_CLN_AUDIO_CTRL_H__ */
-diff --git a/drivers/platform/x86/quark/intel_cln_board_data.c b/drivers/platform/x86/quark/intel_cln_board_data.c
-new file mode 100644
-index 0000000..3888e3e
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_board_data.c
-@@ -0,0 +1,260 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton Legacy Platform Data accessor layer
-+ *
-+ * Simple Legacy SPI flash access layer
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
-+ */
-+
-+#include <asm/io.h>
-+#include <linux/dmi.h>
-+#include <linux/errno.h>
-+#include <linux/ioport.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+
-+#define DRIVER_NAME "board_data"
-+#define PFX "MFH: "
-+#define SPIFLASH_BASEADDR 0xFFF00000
-+#define MFH_OFFSET 0x00008000
-+#define PLATFORM_DATA_OFFSET 0x00010000
-+#define MTD_PART_OFFSET 0x00050000
-+#define MTD_PART_LEN 0x00040000
-+#define MFH_PADDING 0x1E8
-+#define MFH_MAGIC 0x5F4D4648
-+#define FLASH_SIZE 0x00400000
-+
-+/* MFH types supported @ version #1 */
-+#define MFH_ITEM_FW_STAGE1 0x00000000
-+#define MFH_ITEM_FW_STAGE1_SIGNED 0x00000001
-+#define MFH_ITEM_FW_STAGE2 0x00000003
-+#define MFH_ITEM_FW_STAGE2_SIGNED 0x00000004
-+#define MFH_ITEM_FW_STAGE2_CONFIG 0x00000005
-+#define MFH_ITEM_FW_STAGE2_CONFIG_SIGNED 0x00000006
-+#define MFH_ITEM_FW_PARAMS 0x00000007
-+#define MFH_ITEM_FW_RECOVERY 0x00000008
-+#define MFH_ITEM_FW_RECOVERY_SIGNED 0x00000009
-+#define MFH_ITEM_BOOTLOADER 0x0000000B
-+#define MFH_ITEM_BOOTLOADER_SIGNED 0x0000000C
-+#define MFH_ITEM_BOOTLOADER_CONFIG 0x0000000D
-+#define MFH_ITEM_BOOTLOADER_CONFIG_SIGNED 0x0000000E
-+#define MFH_ITEM_KERNEL 0x00000010
-+#define MFH_ITEM_KERNEL_SIGNED 0x00000011
-+#define MFH_ITEM_RAMDISK 0x00000012
-+#define MFH_ITEM_RAMDISK_SIGNED 0x00000013
-+#define MFH_ITEM_LOADABLE_PROGRAM 0x00000015
-+#define MFH_ITEM_LOADABLE_PROGRAM_SIGNED 0x00000016
-+#define MFH_ITEM_BUILD_INFO 0x00000018
-+#define MFH_ITEM_VERSION 0x00000019
-+
-+struct intel_cln_mfh {
-+ u32 id;
-+ u32 ver;
-+ u32 flags;
-+ u32 next_block;
-+ u32 item_count;
-+ u32 boot_priority_list;
-+ u8 padding[MFH_PADDING];
-+};
-+
-+struct intel_cln_mfh_item {
-+ u32 type;
-+ u32 addr;
-+ u32 len;
-+ u32 res0;
-+};
-+
-+struct kobject * board_data_kobj;
-+EXPORT_SYMBOL_GPL(board_data_kobj);
-+
-+static long unsigned int flash_version_data;
-+static ssize_t flash_version_show(struct kobject *kobj,
-+ struct kobj_attribute *attr, char *buf)
-+{
-+ return snprintf(buf, 12, "%#010lx\n", flash_version_data);
-+}
-+
-+static struct kobj_attribute flash_version_attr =
-+ __ATTR(flash_version, 0644, flash_version_show, NULL);
-+
-+extern int intel_cln_plat_probe(struct resource * pres);
-+
-+#define DEFAULT_BOARD "Galileo"
-+
-+static struct platform_device bsp_data [] = {
-+ {
-+ .name = "QuarkEmulation",
-+ .id = -1,
-+ },
-+ {
-+ .name = "ClantonPeakSVP",
-+ .id = -1,
-+ },
-+ {
-+ .name = "KipsBay",
-+ .id = -1,
-+ },
-+ {
-+ .name = "CrossHill",
-+ .id = -1,
-+ },
-+ {
-+ .name = "ClantonHill",
-+ .id = -1,
-+ },
-+ {
-+ .name = "Galileo",
-+ .id = -1,
-+ },
-+
-+};
-+
-+/**
-+ * add_firmware_sysfs_entry
-+ *
-+ * Add an entry in sysfs consistent with Galileo IDE's expected location
-+ * covers current software versions and legacy code < Intel Galileo BIOS 0.9.0
-+ *
-+ */
-+static int add_firmware_sysfs_entry(const char * board_name)
-+{
-+ pr_info("Intel Quark Board %s Firmware Version %#010lx\n",
-+ board_name, flash_version_data);
-+
-+ /* board_data_kobj subordinate of firmware @ /sys/firmware/board_data */
-+ board_data_kobj = kobject_create_and_add("board_data", firmware_kobj);
-+ if (!board_data_kobj) {
-+ pr_err(PFX"kset create error\n");
-+ return -ENODEV;
-+ }
-+ return sysfs_create_file(board_data_kobj, &flash_version_attr.attr);
-+}
-+
-+/**
-+ * intel_cln_board_data_init_legacy
-+ *
-+ * Module entry point for older BIOS versions
-+ * Allows more recent kernels to boot on Galileo boards with BIOS before release
-+ * 0.9.0
-+ */
-+static int __init intel_cln_board_data_init_legacy(void)
-+{
-+ extern struct kobject * firmware_kobj;
-+ struct intel_cln_mfh __iomem * mfh;
-+ struct intel_cln_mfh_item __iomem * item;
-+ struct platform_device * pdev;
-+ u32 i;
-+ char * board_name = NULL;
-+ void __iomem * spi_data;
-+ int ret = 0;
-+
-+ spi_data = ioremap(SPIFLASH_BASEADDR, FLASH_SIZE);
-+ if (!spi_data)
-+ return -ENODEV;
-+
-+ /* get mfh and first item pointer */
-+ mfh = spi_data + MFH_OFFSET;
-+ if (mfh->id != MFH_MAGIC){
-+ pr_err(PFX"Bad MFH magic want 0x%08x found 0x%08x @ 0x%p\n",
-+ MFH_MAGIC, mfh->id, &mfh->id);
-+ return -ENODEV;
-+ }
-+
-+ pr_info(PFX"Booting on an old BIOS assuming %s board\n", DEFAULT_BOARD);
-+ pr_info(PFX"mfh @ 0x%p: id 0x%08lx ver 0x%08lx entries 0x%08lx\n",
-+ mfh, (unsigned long)mfh->id, (unsigned long)mfh->ver,
-+ (unsigned long)mfh->item_count);
-+ item = (struct intel_cln_mfh_item __iomem *)
-+ &mfh->padding [sizeof(u32) * mfh->boot_priority_list];
-+
-+ /* Register a default board */
-+ for (i = 0; i < sizeof(bsp_data)/sizeof(struct platform_device); i++){
-+ if (!strcmp(bsp_data[i].name, DEFAULT_BOARD)){
-+ board_name = (char*)bsp_data[i].name;
-+ platform_device_register(&bsp_data[i]);
-+ }
-+ }
-+
-+ /* Register flash regions as seperate platform devices */
-+ for (i = 0; i < mfh->item_count; i++, item++){
-+ pdev = NULL;
-+
-+ switch (item->type){
-+ case MFH_ITEM_VERSION:
-+ flash_version_data = item->res0;
-+ ret = add_firmware_sysfs_entry(board_name);
-+ break;
-+ default:
-+ break;
-+ }
-+ }
-+ iounmap(spi_data);
-+ return ret;
-+}
-+
-+/**
-+ * intel_cln_board_data_init_legacy
-+ *
-+ * Module entry point for older BIOS versions
-+ */
-+static int __init intel_cln_board_data_init(void)
-+{
-+ bool found = false;
-+ const char * bios_version = dmi_get_system_info(DMI_BIOS_VERSION);
-+ const char * board_name = dmi_get_system_info(DMI_BOARD_NAME);
-+ extern struct kobject * firmware_kobj;
-+ int ret = 0;
-+ u32 i;
-+
-+ /* BIOS later than version 0.9.0 contains the right DMI data */
-+ for (i = 0; board_name != NULL && bios_version != NULL &&
-+ i < sizeof(bsp_data)/sizeof(struct platform_device); i++){
-+
-+ if (!strcmp(bsp_data[i].name, board_name)){
-+
-+ /* Register board */
-+ platform_device_register(&bsp_data[i]);
-+ found = true;
-+
-+ /* Galileo IDE expects this entry */
-+ flash_version_data = simple_strtoul(bios_version, NULL, 16);
-+ ret = add_firmware_sysfs_entry(bsp_data[i].name);
-+
-+ break;
-+ }
-+ }
-+
-+ /* For older BIOS without DMI data we read the data directly from flash */
-+ if (found == false){
-+ ret = intel_cln_board_data_init_legacy();
-+ }
-+
-+ return ret;
-+}
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("Intel Clanton SPI Data API");
-+MODULE_LICENSE("Dual BSD/GPL");
-+subsys_initcall(intel_cln_board_data_init);
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_esram.c b/drivers/platform/x86/quark/intel_cln_esram.c
-new file mode 100644
-index 0000000..76d2024
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_esram.c
-@@ -0,0 +1,1144 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton eSRAM overlay driver
-+ *
-+ * eSRAM is an on-chip fast access SRAM.
-+ *
-+ * This driver provides the ability to map a kallsyms derived symbol of
-+ * arbitrary length or a struct page entitiy.
-+ * A sysfs interface is provided to allow map of kernel structures, without
-+ * having to use the API from your code directly.
-+ *
-+ * Example:
-+ * echo idt_table > /sys/devices/intel-cln-esram.0/map
-+ *
-+ * An API is provided to allow for mapping of a) kernel symbols or b) pages.
-+ * eSRAM requires 4k physically aligned addresses to work - so a struct page
-+ * fits neatly into this.
-+ *
-+ * intel_cln_esram_map_sym(ohci_irq);
-+ * intel_cln_esram_map_page(virt_to_page(ohci_irq), "ohci_irq");
-+ * Are equivalent - with the exception that map_sym() can detect if a mapping
-+ * crosses a page-boundary, whereas map_page just maps one page. Generally use
-+ * map_sym() for code and map_page() for data
-+ *
-+ * To populte eSRAM we must copy data to a temporary buffer, overlay and
-+ * then copy data back to the eSRAM region.
-+ *
-+ * When entering S3 - we must save eSRAM state to DRAM, and similarly on restore
-+ * to S0 we must repopulate eSRAM
-+ * Unmap code is included for reference however the cache coherency of unmap is
-+ * not guaranteed so the functionality is not exported by this code
-+ *
-+ */
-+#include <asm/cacheflush.h>
-+#include <asm/desc.h>
-+#include <asm/io.h>
-+#include <asm/pgtable.h>
-+#include <asm/special_insns.h>
-+#include <asm-generic/uaccess.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/fs.h>
-+#include <linux/intel_cln_sb.h>
-+#include <linux/kallsyms.h>
-+#include <linux/list.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/printk.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm.h>
-+#include <linux/seq_file.h>
-+#include <linux/slab.h>
-+#include <linux/spinlock.h>
-+#include <linux/timer.h>
-+
-+#include "intel_cln_esram.h"
-+
-+#define DRIVER_NAME "intel-cln-esram"
-+
-+/* Shorten fn names to fit 80 char limit */
-+#ifndef sb_read
-+#define sb_read intel_cln_sb_read_reg
-+#endif
-+#ifndef sb_write
-+#define sb_write intel_cln_sb_write_reg
-+#endif
-+
-+/* Define size of pages, ECC scrub demark etc */
-+#define MAX_PAGE_RETRIES (100)
-+#define MS_PER_HOUR (3600000UL)
-+#define ESRAM_PAGE_COUNT INTEL_CLN_ESRAM_PAGE_COUNT
-+#define ESRAM_PAGE_MASK (0xFFFFF000)
-+#define ESRAM_PAGE_SIZE INTEL_CLN_ESRAM_PAGE_SIZE
-+#define ESRAM_TOTAL_SIZE (ESRAM_PAGE_COUNT * ESRAM_PAGE_SIZE)
-+#define ECC_MAX_REFRESH_PERIOD (48)
-+#define ECC_DEFAULT_REFRESH_PERIOD (24)
-+#define ECC_DRAM_READSIZE (512) /* bytes per DRAM ECC */
-+#define ECC_ESRAM_READSIZE ESRAM_PAGE_SIZE /* bytes per SRAM ECC */
-+
-+/* Register ID */
-+#define ESRAM_PGPOOL_REG (0x80) /* PGPOOL */
-+#define ESRAM_CTRL_REG (0x81) /* ESRAMCTRL */
-+#define ESRAM_PGBLOCK_REG (0x82) /* Global page ctrl */
-+#define ESCRM_ECCCERR_REG (0x83) /* Correctable ECC */
-+#define ESRAM_ECCUCERR_REG (0x84) /* Uncorrectable ECC */
-+
-+/* Reg commands */
-+#define ESRAM_CTRL_READ (0x10) /* Config reg */
-+#define ESRAM_CTRL_WRITE (0x11) /* Config reg */
-+#define ESRAM_PAGE_READ (0x12) /* Page config read */
-+#define ESRAM_PAGE_WRITE (0x13) /* Page config write */
-+
-+/* ESRAMPGPOOL reg 0x80 - r/w opcodes 0x10/0x11 */
-+#define ESRAM_PGPOOL_FLUSHING(x) ((x>>18)&0x1FF)
-+#define ESRAM_PGPOOL_PGBUSY(x) ((x>>9)&0x1FF)
-+
-+/* ESRAMCTRL reg 0x81 - r/w opcodes 0x10/0x11 */
-+#define ESRAM_CTRL_FLUSHPRI(x) ((x>>25)&0x03) /* DRAM flush priority */
-+#define ESRAM_CTRL_SIZE(x) ((x>>16)&0xFF) /* # of 4k pages */
-+#define ESRAM_CTRL_ECCTHRESH(x) ((x>>8)&0xFF) /* ECC threshold */
-+#define ESRAM_CTRL_THRESHMSG_EN (0x00000080) /* ECC notification */
-+#define ESRAM_CTRL_ISAVAIL (0x00000010) /* ESRAM on die ? */
-+#define ESRAM_CTRL_BLOCK_MODE (0x00000008) /* Block mode enable */
-+#define ESRAM_CTRL_GLOBAL_LOCK (0x00000004) /* Global lock status */
-+#define ESRAM_CTRL_FLUSHDISABLE (0x00000002) /* Global flush/dis */
-+#define ESRAM_CTRL_SECDEC (0x00000001) /* ECC enable bit */
-+
-+/* PGBLOCK reg 0x82 - opcode 0x10/0x11 */
-+#define ESRAM_PGBLOCK_FLUSHEN (0x80000000) /* Block flush enable */
-+#define ESRAM_PGBLOCK_PGFLUSH (0x40000000) /* Flush the block */
-+#define ESRAM_PGBLOCK_DISABLE (0x20000000) /* Block mode disable */
-+#define ESRAM_PGBLOCK_ENABLE (0x10000000) /* Block mode enable */
-+#define ESRAM_PGBLOCK_LOCK (0x08000000) /* Block mode lock en */
-+#define ESRAM_PGBLOCK_INIT (0x04000000) /* Block init in prog */
-+#define ESRAM_PGBLOCK_BUSY (0x01000000) /* Block is enabled */
-+#define ESRAM_PGBLOCK_SYSADDR(x) (x&0x000000FF)
-+
-+/* ESRAMPGCTRL - opcode 0x12/0x13 */
-+#define ESRAM_PAGE_FLUSH_PAGE_EN (0x80000000) /* S3 autoflush */
-+#define ESRAM_PAGE_FLUSH (0x40000000) /* Flush page to DRAM */
-+#define ESRAM_PAGE_DISABLE (0x20000000) /* page disable bit */
-+#define ESRAM_PAGE_EN (0x10000000) /* Page enable */
-+#define ESRAM_PAGE_LOCK (0x08000000) /* Page lock en */
-+#define ESRAM_PAGE_INITIALISING (0x04000000) /* Init in progress */
-+#define ESRAM_PAGE_BUSY (0x01000000) /* Page busy */
-+#define ESRAM_PAGE_MAP_SHIFT (12) /* Shift away 12 LSBs */
-+
-+/* Extra */
-+#define ESRAM_MAP_OP (0x01)
-+#define ESRAM_UNMAP_OP (0x00)
-+
-+/**
-+ * struct esram_refname
-+ *
-+ * Structure to hold a linked list of names
-+ */
-+struct esram_refname {
-+ char name[KSYM_SYMBOL_LEN]; /* Name of mapping */
-+ struct list_head list;
-+};
-+
-+/**
-+ * struct esram_page
-+ *
-+ * Represents an eSRAM page in our linked list
-+ */
-+struct esram_page {
-+
-+ struct list_head list; /* List entry descriptor */
-+ struct list_head name_list; /* Linked list for name references */
-+ u32 id; /* Page ID */
-+ u32 phys_addr; /* Physial address of page */
-+ u32 refcount; /* Reference count */
-+ u32 vaddr; /* Virtual address of page */
-+
-+};
-+
-+/**
-+ * struct intel_cln_esram_dev
-+ *
-+ * Structre to represent module state/data/etc
-+ */
-+struct intel_cln_esram_dev{
-+
-+ /* Linux kernel structures */
-+ struct list_head page_used; /* Used pages */
-+ struct list_head page_free; /* Free pages */
-+ spinlock_t slock; /* Spinlock */
-+ struct platform_device *pldev; /* Platform device */
-+
-+ /* Actual data */
-+ struct esram_page * pages;
-+ u8 cbuf[ESRAM_PAGE_SIZE];
-+
-+ /* Stats */
-+ u32 page_count; /* As reported by silicon */
-+ u32 page_disable_retries; /* Aggreate count on disable */
-+ u32 page_enable_retries; /* Aggregate spin count page enable */
-+ u32 page_free_ct; /* Free pages for mapping code section */
-+};
-+
-+static struct intel_cln_esram_dev esram_dev;
-+
-+/*
-+ * Kallsyms does not provide data addresses. To map important structures such as
-+ * the idt and gdt, we need to frig the lookup with the below. Other entities
-+ * can similarly be added. Note we map a page from the given address - anything
-+ * larger will require additional code to handle
-+ */
-+struct esram_symex {
-+ char * name;
-+ void * vaddr;
-+ u32 size;
-+};
-+
-+static struct esram_symex esram_symex[] =
-+{
-+ {
-+ .name = "idt_table",
-+ .vaddr = &idt_table,
-+ .size = ESRAM_PAGE_SIZE,
-+ },
-+ {
-+ .name = "gdt_page",
-+ .vaddr = &gdt_page,
-+ .size = ESRAM_PAGE_SIZE,
-+ },
-+};
-+
-+/**
-+ * intel_cln_esram_stat_show
-+ *
-+ * @param dev: pointer to device
-+ * @param attr: attribute pointer
-+ * @param buf: output buffer
-+ * @return number of bytes successfully read
-+ *
-+ * Populates eSRAM state via /sys/device/intel-cln-esram.0/stat
-+ */
-+static ssize_t intel_cln_esram_stat_show(struct device *dev,
-+ struct device_attribute *attr,
-+ char *buf)
-+
-+{
-+ struct esram_page * epage = NULL;
-+ int len = 0;
-+ unsigned int count = PAGE_SIZE, size;
-+ u32 pgpool = 0, ctrl = 0, pgblock = 0;
-+ char * enabled = "enabled";
-+ char * disabled = "disabled";
-+
-+ /* Display page-pool relevant data */
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGPOOL_REG, &pgpool, 1);
-+ size = snprintf(buf, count,
-+ "esram-pgpool\t\t\t: 0x%08x\n"
-+ "esram-pgpool.free\t\t: %u\n"
-+ "esram-pgpool.flushing\t\t: %u\n",
-+ pgpool, ESRAM_PGPOOL_PGBUSY(pgpool)+1,
-+ ESRAM_PGPOOL_FLUSHING(pgpool) + 1);
-+ len += size;
-+ count -= size;
-+
-+ /* Display ctrl reg - most of this is of interest */
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
-+ size = snprintf(buf + len, count - len,
-+ "esram-ctrl\t\t\t: 0x%08x\n"
-+ "esram-ctrl.ecc\t\t\t: %s\n"
-+ "esram-ctrl.ecc-theshold\t\t: %u\n"
-+ "esram-ctrl.pages\t\t: %u\n"
-+ "esram-ctrl.dram-flush-priorityi\t: %u\n",
-+ ctrl, (ctrl & ESRAM_CTRL_SECDEC) ? enabled : disabled,
-+ ESRAM_CTRL_ECCTHRESH(ctrl), ESRAM_CTRL_SIZE(ctrl)+1,
-+ ESRAM_CTRL_FLUSHPRI(ctrl));
-+ len += size;
-+ count -= size;
-+
-+ /* Display block ctrl/stat - we should be !block mode */
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &pgblock, 1);
-+ size = snprintf(buf + len, count - len, "esram-block\t\t\t: 0x%08x\n",
-+ pgblock);
-+ len += size;
-+ count -= size;
-+
-+ /* Print ECC status regs */
-+
-+ /* Print per-page info */
-+ size = snprintf(buf + len, count - len,
-+ "free page\t\t\t: %u\nused page\t\t\t: %u\n"
-+ "refresh \t\t\t: %ums\npage enable retries\t\t: %u\n"
-+ "page disable retries\t: %u\n",
-+ esram_dev.page_free_ct,
-+ esram_dev.page_count-esram_dev.page_free_ct,
-+ 0,
-+ esram_dev.page_enable_retries,
-+ esram_dev.page_disable_retries);
-+ len += size;
-+ count -= size;
-+
-+ spin_lock(&esram_dev.slock);
-+ if(!list_empty(&esram_dev.page_free)){
-+
-+ epage = list_first_entry(&esram_dev.page_free, struct esram_page, list);
-+ size = snprintf(buf + len, count - len,
-+ "ecc next page \t\t\t: %u\n",epage->id);
-+ len += size;
-+ count -= size;
-+
-+
-+ }
-+ spin_unlock(&esram_dev.slock);
-+
-+ /* Return len indicate eof */
-+ return len;
-+}
-+
-+/**
-+ * intel_cln_esram_map_show
-+ *
-+ * @param dev: pointer to device
-+ * @param attr: attribute pointer
-+ * @param buf: output buffer
-+ * @return number of bytes successfully read
-+ *
-+ * Read back eSRAM mapped entries
-+ */
-+static ssize_t
-+intel_cln_esram_map_show(struct device *dev,struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct esram_page * epage = NULL;
-+ struct esram_refname * refname = NULL;
-+ int len = 0, size = 0;
-+ unsigned int count = PAGE_SIZE;
-+
-+ spin_lock(&esram_dev.slock);
-+ list_for_each_entry(epage, &esram_dev.page_used, list){
-+ /* Print references */
-+ list_for_each_entry(refname, &epage->name_list, list){
-+ size = snprintf(buf + len, count - len,
-+ "%s ", refname->name);
-+ len += size;
-+ count -= size;
-+ }
-+ /* Print data */
-+ size += snprintf(buf + len, count - len,
-+ "\n\tPage virt 0x%08x phys 0x%08x\n"
-+ "\tRefcount %u\n",
-+ epage->vaddr, epage->phys_addr,
-+ epage->refcount);
-+ len += size;
-+ count -= size;
-+ }
-+ spin_unlock(&esram_dev.slock);
-+
-+ /* Return len indicate eof */
-+ return len;
-+}
-+
-+/**
-+ * intel_cln_esram_map_store
-+ *
-+ * @param dev: pointer to device
-+ * @param attr: attribute pointer
-+ * @param buf: input buffer
-+ * @param size: size of input data
-+ * @return number of bytes successfully written
-+ *
-+ * Function allows user-space to switch mappings on/off with a simple
-+ * echo idt_table > /sys/devices/intel-cln-esram.0/map type command
-+ */
-+static ssize_t
-+intel_cln_esram_map_store(struct device *dev, struct device_attribute *attr,
-+ const char *buf, size_t size)
-+{
-+ ssize_t ret = 0;
-+ char * sbuf = NULL;
-+ unsigned long vaddr = 0, i = 0;
-+ unsigned int count = PAGE_SIZE;
-+
-+ if(count <= 1){
-+ return -EINVAL;
-+ }
-+
-+ /* Get input */
-+ sbuf = (char*)buf;
-+
-+ /* Fixup entity to scrub spaces */
-+ while(sbuf < (buf + count)){
-+ if(*sbuf == ' ' || *sbuf == '\r' || *sbuf =='\n'){
-+ *sbuf = 0;
-+ break;
-+ }
-+ sbuf++;
-+ }
-+
-+ /* Check to see if we are being asked to map a non-kallsyms addr */
-+ for(i = 0; i < sizeof(esram_symex)/sizeof(struct esram_symex); i++){
-+ if(strcmp(buf, esram_symex[i].name) == 0){
-+ ret = intel_cln_esram_map_range(
-+ esram_symex[i].vaddr,
-+ esram_symex[i].size,
-+ esram_symex[i].name);
-+ goto done;
-+ }
-+ }
-+
-+ /* This path relies on kallsyms to provide name/address data */
-+ vaddr = kallsyms_lookup_name(buf);
-+ if(vaddr == 0)
-+ goto done;
-+
-+ ret = intel_cln_esram_map_symbol((void*)vaddr);
-+done:
-+ if(ret == 0)
-+ ret = (ssize_t)count;
-+ return ret;
-+}
-+
-+static struct device_attribute dev_attr_stats = {
-+ .attr = {
-+ .name = "stats",
-+ .mode = 0444,
-+ },
-+ .show = intel_cln_esram_stat_show,
-+};
-+
-+static struct device_attribute dev_attr_map = {
-+ .attr = {
-+ .name = "map",
-+ .mode = 0644,
-+ },
-+ .show = intel_cln_esram_map_show,
-+ .store = intel_cln_esram_map_store,
-+};
-+
-+static struct attribute *platform_attributes[] = {
-+ &dev_attr_stats.attr,
-+ &dev_attr_map.attr,
-+ NULL,
-+};
-+
-+static struct attribute_group esram_attrib_group = {
-+ .attrs = platform_attributes
-+};
-+
-+/******************************************************************************
-+ * eSRAM Core
-+ ******************************************************************************/
-+
-+/**
-+ * intel_cln_esram_page_busy
-+ *
-+ * @param epage: Pointer to the page descriptor
-+ * @return boolean indicating whether or not a page is enabled
-+ */
-+static int intel_cln_esram_page_busy(struct esram_page * epage, u8 lock)
-+{
-+ u32 reg = 0;
-+
-+ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, epage->id, &reg, lock);
-+ return (reg&(ESRAM_PAGE_BUSY | ESRAM_PAGE_FLUSH | ESRAM_PAGE_DISABLE));
-+}
-+
-+/**
-+ * intel_cln_esram_fault
-+ *
-+ * Dump eSRAM registers and kernel panic
-+ * Nothing else to do at this point
-+ */
-+void intel_cln_esram_fault(struct esram_page * epage, u32 lineno)
-+{
-+ u32 reg = 0, next = 0, prev = 0, prev_reg = 0;
-+ u32 next_reg = 0, block = 0, ctrl = 0;
-+
-+ pr_err("eSRAM: fault @ %s:%d\n", __FILE__, lineno);
-+ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, epage->id, &reg, 1);
-+ pr_err("read page %d state 0x%08x\n", epage->id, reg);
-+ if(epage->id == 0){
-+ next = 1; prev = 127;
-+ }else if(epage->id == 127){
-+ next = 0; prev = 126;
-+ }else{
-+ next = epage->id+1;
-+ prev = epage->id-1;
-+ }
-+ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, next, &next_reg, 1);
-+ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, prev, &prev_reg, 1);
-+
-+ /* Get state */
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &block, 1);
-+
-+ pr_err("eSRAM: CTRL 0x%08x block 0x%08x\n", ctrl, block);
-+ pr_err("Prev page %d state 0x%08x Next page %d state 0x%08x\n"
-+ , next, next_reg, prev, prev_reg);
-+ BUG();
-+}
-+
-+
-+/**
-+ * intel_cln_esram_page_enable
-+ *
-+ * @param epage: struct esram_page carries data to program to register
-+ * @param lock: Indicates whether to attain sb spinlock or not
-+ *
-+ * Enable an eSRAM page spinning for page to become ready.
-+ */
-+static void intel_cln_esram_page_enable(struct esram_page *epage, u8 lock)
-+{
-+ u32 ret = 0;
-+
-+ /* Fault if we try to enable a disabled page */
-+ if(intel_cln_esram_page_busy(epage, lock)){
-+ intel_cln_esram_fault(epage, __LINE__);
-+ }
-+
-+ /* Program page mapping */
-+ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
-+ ESRAM_PAGE_FLUSH_PAGE_EN | ESRAM_PAGE_EN |
-+ (epage->phys_addr>>ESRAM_PAGE_MAP_SHIFT), lock);
-+ do {
-+ /* Poll until page busy bit becomes true */
-+ ret = intel_cln_esram_page_busy(epage, lock);
-+
-+ /* This branch should rarely if ever be true */
-+ if(unlikely(ret == 0)){
-+ esram_dev.page_enable_retries++;
-+ }
-+
-+ }while(ret == 0);
-+}
-+
-+/**
-+ * intel_cln_esram_page_disable_sync
-+ *
-+ * @param epage: pointer to eSRAM page descriptor
-+ *
-+ * This function spins waiting for disable bit to clear, useful right after a
-+ * disable/disable-flush command. Interrupts are enabled here, sleeping is OK
-+ */
-+static void intel_cln_esram_page_disable_sync(struct esram_page * epage)
-+{
-+ u32 ret = 0, retries = 0;
-+ do {
-+ /* Poll for busy bit clear */
-+ ret = intel_cln_esram_page_busy(epage, 1);
-+
-+ /* This branch should rarely if ever be true */
-+ if(unlikely(ret)){
-+ esram_dev.page_disable_retries++;
-+ retries++;
-+ }
-+
-+ if(retries == MAX_PAGE_RETRIES){
-+ intel_cln_esram_fault(epage, __LINE__);
-+ }
-+ }while(ret);
-+}
-+
-+/**
-+ * intel_cln_esram_page_disable
-+ *
-+ * @param epage: struct esram_page carries data to program to register
-+ *
-+ * Disable the eSRAM page no flush. Interrupts are enabled here, sleeping is OK
-+ */
-+static void intel_cln_esram_page_disable(struct esram_page *epage)
-+{
-+ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
-+ ESRAM_PAGE_DISABLE, 1);
-+ intel_cln_esram_page_disable_sync(epage);
-+}
-+
-+/**
-+ * intel_cln_esram_page_flush_disable
-+ *
-+ * @param epage: struct esram_page carries data to program to register
-+ *
-+ * Disable the eSRAM page - with flush. Note the architecture will block access
-+ * to the overlayed region until the flush has completed => irqs may be switched
-+ * on during this operation.
-+ */
-+static void intel_cln_esram_page_flush_disable(struct esram_page *epage)
-+{
-+
-+
-+ /* Do flush */
-+ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
-+ ESRAM_PAGE_FLUSH | ESRAM_PAGE_DISABLE, 1);
-+
-+ intel_cln_esram_page_disable_sync(epage);
-+}
-+
-+#if 0
-+/**
-+ * intel_cln_esram_flush_disable_all
-+ *
-+ * Flushes and disables all enabled eSRAM pages
-+ */
-+static void intel_cln_esram_page_flush_disable_all(void)
-+{
-+ struct esram_page * epage = NULL;
-+
-+ spin_lock(&esram_dev.slock);
-+ list_for_each_entry(epage, &esram_dev.page_used, list){
-+ intel_cln_esram_page_flush_disable(epage);
-+ }
-+ spin_unlock(&esram_dev.slock);
-+}
-+#endif
-+
-+/**
-+ * intel_cln_esram_page_populate_atomic
-+ *
-+ * @param epage: Pointer to eSRAM page desciptor.
-+ * @return 0 placeholder, later versions may return error
-+ *
-+ * Function takes the mappings given in epage and uses the values to populate
-+ * an eSRAM page. The copy/enable/copy routine must be done atomically, since we
-+ * may be doing a memcpy() of an ISR for example.
-+ * For this reason we wrapper this entire call into a callback provided by
-+ * side-band, which does a spin_lock_irqsave calls this function and then does
-+ * a spin_lock_irqrestore - thus guaranteeing atomicity of the below code and
-+ * respect for the locking strategy of the side-band driver
-+ */
-+static int intel_cln_esram_page_populate_atomic(struct esram_page * epage)
-+{
-+ unsigned long crz;
-+
-+ /* Copy away */
-+ memcpy(&esram_dev.cbuf, (void*)epage->vaddr, ESRAM_PAGE_SIZE);
-+
-+ /* If CR0.WP is true - flip it HSD # 4930660 */
-+ crz = read_cr0();
-+ if (crz & X86_CR0_WP){
-+ write_cr0(crz & (~X86_CR0_WP));
-+ }
-+
-+ /* Disable NMI */
-+ outb(0x80, 0x70);
-+
-+ /* Enable page mapping */
-+ intel_cln_esram_page_enable(epage, 0);
-+
-+ /* Copy back - populating memory overlay */
-+ memcpy((void*)epage->vaddr, &esram_dev.cbuf, ESRAM_PAGE_SIZE);
-+
-+ /* Re-enable NMI */
-+ outb(0x00, 0x70);
-+
-+ /* Restore CR0.WP if appropriate HSD # 4930660 */
-+ if (crz & X86_CR0_WP){
-+ write_cr0(crz);
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_esram_page_populate
-+ *
-+ * @param epage: Pointer to eSRAM page desciptor.
-+ * @return 0 on success < 0 on failure
-+ *
-+ * Populates the page. set_memory_rw/set_memory_ro require local irqs enabled.
-+ * intel_cln_esram_page_populate_atomic - needs irqs switched off since memory
-+ * can be inconsistent during the populate operation. Depopulate operations are
-+ * architecturally guaranteed
-+ */
-+static int intel_cln_esram_page_populate(struct esram_page * epage)
-+{
-+ int flip_rw = 0, level = 0, ret = 0;
-+ pte_t * pte = epage != NULL ? lookup_address(epage->vaddr, &level):NULL;
-+
-+ if(unlikely(pte == NULL)){
-+ return -EINVAL;
-+ }
-+
-+ /* Determine if we need to set writable */
-+ flip_rw = !(pte_write(*pte));
-+
-+ /* Ensure memory is r/w - do so before spin_lock_irqsave */
-+ if(flip_rw){
-+ ret = set_memory_rw(epage->vaddr, 1);
-+ if (ret != 0){
-+ pr_err("%s error during set_memory_rw = %d\n",
-+ __func__, ret);
-+ return ret;
-+ }
-+ }
-+
-+ /* Force ECC update @ disable only */
-+ intel_cln_esram_page_enable(epage, 1);
-+ intel_cln_esram_page_disable(epage);
-+
-+ /* Enable and populate eSRAM page using callback in sb with irqs off */
-+ ret |= intel_cln_sb_runfn_lock(
-+ (int (*)(void*))intel_cln_esram_page_populate_atomic,(void*)epage);
-+
-+ /* If we set memory writable - restore previous state */
-+ if(flip_rw){
-+ ret |= set_memory_ro(epage->vaddr, 1);
-+ if (ret != 0){
-+ pr_err("%s error during set_memory_ro = %d\n",
-+ __func__, ret);
-+ return ret;
-+ }
-+ }
-+
-+ return ret;
-+}
-+/**
-+ * intel_cln_esram_page_addref
-+ *
-+ * @param epage: eSRAM page descriptor
-+ * @param name: Name of reference to add
-+ * @return zero on success negative on error
-+ *
-+ */
-+static int intel_cln_esram_page_addref(struct esram_page * epage, char * name)
-+{
-+ struct esram_refname * refname = NULL;
-+ if(unlikely(epage == NULL || name == NULL)){
-+ return -EINVAL;
-+ }
-+
-+ refname = kzalloc(sizeof(struct esram_refname), GFP_KERNEL);
-+ if(unlikely(refname == NULL)){
-+ return -ENOMEM;
-+ }
-+
-+ /* Add to list */
-+ strncpy(refname->name, name, sizeof(refname->name));
-+ list_add(&refname->list, &epage->name_list);
-+
-+ /* Bump reference count */
-+ epage->refcount++;
-+ return 0;
-+}
-+
-+
-+/**
-+ * __intel_cln_esram_map_page
-+ *
-+ * @param page: Page to map
-+ * @param name: Name of the mapping
-+ * @return 0 success < 0 failure
-+ *
-+ * Overlay a vritual address rangne eeds to be aligned to a 4k address.
-+ * Since multiple items can live in a 4k range, it is possible when calling
-+ * into map_page() that a previous mapping will have already covered some or all
-+ * of the mapping we want. This is not an error case, if the map function finds
-+ * it is being asked to map a 4k range already mapped it returns 0, to indicate
-+ * the mapping has suceeded i.e. it's already been mapped. This is logical if
-+ * you think about it. In contrast being asked to unmap a region not mapped is
-+ * clearly an error...
-+ *
-+ */
-+static int __intel_cln_esram_map_page(u32 vaddr, char * name)
-+{
-+ int ret = 0;
-+ struct esram_page * epage = NULL;
-+ struct esram_refname * refname = NULL;
-+
-+ if(unlikely(name == NULL)){
-+ return -EINVAL;
-+ }
-+
-+ if(unlikely(esram_dev.page_free_ct == 0)){
-+ return -ENOMEM;
-+ }
-+
-+ /* Verify if we have already mapped */
-+ list_for_each_entry(epage, &esram_dev.page_used, list){
-+ if(epage->vaddr == vaddr){
-+
-+ /* Page already mapped */
-+ list_for_each_entry(refname, &epage->name_list, list){
-+ if(strcmp(refname->name, name)==0){
-+ /* Page mapped at this name */
-+ return -EINVAL;
-+ }
-+ }
-+ /* New symbol in previous mapping */
-+ return intel_cln_esram_page_addref(epage, name);
-+ }
-+ }
-+
-+ /* Enumerate eSRAM page structure */
-+ epage = list_first_entry(&esram_dev.page_free, struct esram_page, list);
-+ epage->phys_addr = virt_to_phys((void*)vaddr);
-+ epage->vaddr = vaddr;
-+ ret = intel_cln_esram_page_addref(epage, name);
-+ if(unlikely(ret < 0)){
-+ return ret;
-+ }
-+
-+ /* Populate page */
-+ ret = intel_cln_esram_page_populate(epage);
-+
-+ /* Move to used list */
-+ list_move(&epage->list, &esram_dev.page_used);
-+ esram_dev.page_free_ct--;
-+
-+ return ret;
-+}
-+
-+/**
-+ * __intel_cln_esram_unmap_page
-+ *
-+ * @param page: Page to unmap
-+ * @param name: Name of the mapping
-+ * @return 0 success < 0 failure
-+ *
-+ * Unmap a previously mapped virutal address range.
-+ * Must be 4k aligned
-+ *
-+ */
-+static int __intel_cln_esram_unmap_page(u32 vaddr, char * name)
-+{
-+ u8 found = 0;
-+ struct esram_page * epage = NULL;
-+ struct esram_refname * refname = NULL;
-+
-+ /* Find physical address */
-+ list_for_each_entry(epage, &esram_dev.page_used, list){
-+ if(epage->vaddr == vaddr){
-+ found = 1;
-+ break;
-+ }
-+ }
-+
-+ /* Bail out on error */
-+ if(found == 0){
-+ pr_err("0x%08x not mapped\n", vaddr);
-+ return -EINVAL;
-+ }
-+
-+ /* Determine reference to delete */
-+ found = 0;
-+ list_for_each_entry(refname, &epage->name_list, list){
-+ if(strcmp(refname->name,name)==0){
-+ found = 1;
-+ break;
-+ }
-+ }
-+ if(unlikely(found == 0)){
-+ pr_err("No mapping %s!\n", name);
-+ return -EINVAL;
-+ }
-+
-+ /* Remove entry decrement reference count */
-+ list_del(&refname->list);
-+ kfree(refname);
-+ if(--epage->refcount > 0){
-+ return 0;
-+ }
-+
-+ /* Flush and disable page */
-+ intel_cln_esram_page_flush_disable(epage);
-+
-+ /* Move to free list tail - scrub entries come from head */
-+ list_move_tail(&epage->list, &esram_dev.page_free);
-+ esram_dev.page_free_ct++;
-+
-+ return 0;
-+}
-+
-+/**
-+ *
-+ * __intel_cln_esram_page_op
-+ *
-+ * @param vaddr: Virtual address of symbol
-+ * @param size: Size/length of symbol
-+ * @param name: Name of mapping
-+ * @param map: Boolean indicates whether to map or unmap the page
-+ * @return 0 success < 0 failure
-+ *
-+ * This function maps/unmaps a pages/pages given at the given vaddr. If
-+ * the extent of the symbol @ vaddr crosses a page boundary, then we map
-+ * multiple pages. Other stuff inside the page, gets a performance boost 'for
-+ * free'. Any other data in the page that crosses the physical page boundary
-+ * will be partially mapped.
-+ */
-+static int __intel_cln_esram_page_op(u32 vaddr, u32 size, char *name, u8 map)
-+{
-+ unsigned long offset = 0, page_offset = 0;
-+ u32 pages = size/ESRAM_PAGE_SIZE + ((size%ESRAM_PAGE_SIZE) ? 1 : 0);
-+ int ret = 0;
-+
-+ /* Compare required pages to available pages */
-+ if(map == ESRAM_MAP_OP){
-+ if(pages > esram_dev.page_free_ct)
-+ return -ENOMEM;
-+ }else{
-+ if(pages > esram_dev.page_count - esram_dev.page_free_ct)
-+ return -ENOMEM;
-+ }
-+
-+ /* Align to 4k and iterate the mappings */
-+ vaddr = vaddr&ESRAM_PAGE_MASK;
-+ while(size > 0){
-+
-+ /* Map the page */
-+ spin_lock(&esram_dev.slock);
-+ if(map == ESRAM_MAP_OP){
-+ ret = __intel_cln_esram_map_page(vaddr, name);
-+
-+ }else{
-+ ret = __intel_cln_esram_unmap_page(vaddr, name);
-+ }
-+ spin_unlock(&esram_dev.slock);
-+ if(unlikely(ret != 0)){
-+ break;
-+ }
-+
-+ /* Calc appropriate offsets */
-+ page_offset = offset_in_page(vaddr);
-+ if(page_offset + size > ESRAM_PAGE_SIZE){
-+
-+ offset = ESRAM_PAGE_SIZE - page_offset;
-+ size -= offset;
-+ vaddr += ESRAM_PAGE_SIZE;
-+
-+ }else{
-+ size = 0;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+/******************************************************************************
-+ * eSRAM API
-+ ******************************************************************************/
-+
-+/**
-+ * intel_cln_esram_map_range
-+ *
-+ * @param vaddr: Virtual address to start mapping (must be 4k aligned)
-+ * @param size: Size to map from
-+ * @param mapname: Mapping name
-+ * @return 0 success < 0 failure
-+ *
-+ * Map 4k increments at given address to eSRAM.
-+ */
-+int intel_cln_esram_map_range(void * vaddr, u32 size, char * mapname)
-+{
-+ if(size == 0 || mapname == NULL || vaddr == NULL){
-+ return -EINVAL;
-+ }
-+ return __intel_cln_esram_page_op((u32)vaddr, size, mapname, ESRAM_MAP_OP);
-+}
-+EXPORT_SYMBOL(intel_cln_esram_map_range);
-+
-+/**
-+ * intel_cln_esram_map_symbol
-+ *
-+ * @param vaddr: Virtual address of the symbol
-+ * @return 0 success < 0 failure
-+ *
-+ * Maps a series of 4k chunks starting at vaddr&0xFFFFF000. vaddr shall be a
-+ * kernel text section symbol (kernel or loaded module)
-+ *
-+ * We get the size of the symbol from kallsyms. We guarantee to map the entire
-+ * size of the symbol - plus whatever padding is necessary to get alignment to
-+ * eSRAM_PAGE_SIZE
-+ * Other stuff inside the mapped pages will get a performance boost 'for free'.
-+ * If this free boost is not what you want then
-+ *
-+ * 1. Align to 4k
-+ * 2. Pad to 4k
-+ * 3. Call intel_cln_esram_map_range()
-+ */
-+int intel_cln_esram_map_symbol(void * vaddr)
-+{
-+ long unsigned int size = 0, offset = 0;
-+ char symname[KSYM_SYMBOL_LEN];
-+
-+ kallsyms_lookup_size_offset((long unsigned int)vaddr, &size, &offset);
-+ if(size == 0){
-+ return -EINVAL;
-+ }
-+ sprint_symbol(symname, (u32)vaddr);
-+
-+ return __intel_cln_esram_page_op((u32)vaddr, size, symname, 1);
-+}
-+EXPORT_SYMBOL(intel_cln_esram_map_symbol);
-+
-+/******************************************************************************
-+ * Module/PowerManagement hooks
-+ ******************************************************************************/
-+
-+/**
-+ * intel_cln_esram_suspend
-+ *
-+ * @param pdev: Platform device structure (unused)
-+ * @param pm: Power managment descriptor
-+ * @return 0 success < 0 failure
-+ *
-+ * For each enabled page - flush to DRAM and disable eSRAM page.
-+ * For each 4k region the architecture guarantees atomicity of flush/disable.
-+ * Hence any memory transactions to the affected region will stall until
-+ * flush/disable completes - hence interrupts are left on.
-+ */
-+static int intel_cln_esram_suspend(struct device * pdev)
-+{
-+ /* Flush and disable of eSRAM pages is carried out automatically */
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_esram_resume
-+ *
-+ * @param pm: Power management descriptor
-+ * @return 0 success < 0 failure
-+ *
-+ * Runs after resume_noirq. Switches pages back to ro, if appropriate. We do
-+ * this here since interrupts will be on, as required by the function
-+ * set_memory_ro. If it were possible to set memory ro in resume_noirq we would
-+ * do it there instead
-+ */
-+static int intel_cln_esram_resume(struct device * pdev)
-+{
-+ struct esram_page * epage = NULL;
-+ int ret = 0;
-+
-+ list_for_each_entry(epage, &esram_dev.page_used, list){
-+ ret |= intel_cln_esram_page_populate(epage);
-+ }
-+
-+ return ret;
-+}
-+
-+
-+/**
-+ * intel_cln_esram_probe
-+ *
-+ * @param pdev: Platform device
-+ * @return 0 success < 0 failure
-+ *
-+ * Callback from platform sub-system to probe
-+ *
-+ * This driver manages eSRAM on a per-page basis. Therefore if we find block
-+ * mode is enabled, or any global, block-level or page-level locks are in place
-+ * at module initialisation time - we bail out.
-+ */
-+static int intel_cln_esram_probe(struct platform_device * pdev)
-+{
-+ int ret = 0;
-+ u32 block = 0, ctrl = 0, i = 0, pgstat = 0;
-+
-+ memset(&esram_dev, 0x00, sizeof(esram_dev));
-+ INIT_LIST_HEAD(&esram_dev.page_used);
-+ INIT_LIST_HEAD(&esram_dev.page_free);
-+ spin_lock_init(&esram_dev.slock);
-+ esram_dev.page_free_ct = 0;
-+
-+ /* Ensure block mode disabled */
-+ block = ESRAM_PGBLOCK_DISABLE;
-+ sb_write(SB_ID_ESRAM, ESRAM_CTRL_WRITE, ESRAM_PGBLOCK_REG, block, 1);
-+
-+ /* Get state */
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
-+ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &block, 1);
-+
-+ /* Verify state is good to go */
-+ if (ctrl & ESRAM_CTRL_GLOBAL_LOCK){
-+ pr_err ("eSRAM: global lock @ 0x%08x\n", ctrl);
-+ return -ENODEV;
-+ }
-+
-+ if (block & (ESRAM_PGBLOCK_LOCK | ESRAM_PGBLOCK_ENABLE)){
-+ pr_err ("eSRAM: lock @ 0x%08x\n", block);
-+ return -ENODEV;
-+ }
-+ pr_info("eSRAM: CTRL 0x%08x block 0x%08x\n", ctrl, block);
-+
-+ /* Calculate # of pages silicon supports */
-+ esram_dev.page_count = ESRAM_CTRL_SIZE(ctrl) + 1;
-+ esram_dev.page_free_ct = esram_dev.page_count;
-+ pr_info("eSRAM: pages %d\n", esram_dev.page_free_ct);
-+
-+ if(esram_dev.page_free_ct <= 1){
-+ pr_err("Too few pages reported by eSRAM sub-system\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Allocate an appropriate number of pages */
-+ esram_dev.pages = kzalloc(esram_dev.page_count *
-+ sizeof(struct esram_page), GFP_KERNEL);
-+ if (esram_dev.pages == NULL){
-+ return -ENOMEM;
-+ }
-+
-+ /* Initialise list of free pages, explicitely disable as we go */
-+ for(i = 0; i < esram_dev.page_count; i++){
-+ INIT_LIST_HEAD(&esram_dev.pages[i].name_list);
-+ esram_dev.pages[i].id = i;
-+
-+ /* Read & verify page state */
-+ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, i, &pgstat, 1);
-+ if(pgstat & (ESRAM_PAGE_BUSY | ESRAM_PAGE_LOCK)){
-+ pr_err("eSRAM: page %d state 0x%08x err\n", i, pgstat);
-+ ret = -ENODEV;
-+ goto err;
-+ }
-+
-+ list_add(&esram_dev.pages[i].list, &esram_dev.page_free);
-+ }
-+
-+ ret = sysfs_create_group(&pdev->dev.kobj, &esram_attrib_group);
-+ if (ret)
-+ goto err;
-+
-+ return 0;
-+err:
-+ kfree(esram_dev.pages);
-+ return ret;
-+}
-+
-+/*
-+ * Power management operations
-+ */
-+static const struct dev_pm_ops intel_cln_esram_pm_ops = {
-+ .suspend = intel_cln_esram_suspend,
-+ .resume = intel_cln_esram_resume,
-+};
-+
-+/*
-+ * Platform structures useful for interface to PM subsystem
-+ */
-+static struct platform_driver intel_cln_esram_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ .pm = &intel_cln_esram_pm_ops,
-+ },
-+ .probe = intel_cln_esram_probe,
-+};
-+
-+module_platform_driver(intel_cln_esram_driver);
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
-+MODULE_DESCRIPTION("Intel Clanton eSRAM overlay/ECC-scrub driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_esram.h b/drivers/platform/x86/quark/intel_cln_esram.h
-new file mode 100644
-index 0000000..af6156a
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_esram.h
-@@ -0,0 +1,107 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton eSRAM overlay driver
-+ *
-+ * eSRAM is an on-chip fast access SRAM.
-+ *
-+ * This driver provides the ability to map a kallsyms derived symbol of
-+ * arbitrary length or a struct page entitiy.
-+ * A proc interface is provided to allow map/unmap of kernel structures, without
-+ * having to use the API from your code directly.
-+ *
-+ * Example:
-+ * echo ehci_irq on > /proc/driver/esram/map
-+ * echo ehci_irq off > /proc/driver/esram/map
-+ *
-+ * An API is provided to allow for mapping of a) kernel symbols or b) pages.
-+ * eSRAM requires 4k physically aligned addresses to work - so a struct page
-+ * fits neatly into this.
-+ *
-+ * To populte eSRAM we must copy data to a temporary buffer, overlay and
-+ * then copy data back to the eSRAM region.
-+ *
-+ * When entering S3 - we must save eSRAM state to DRAM, and similarly on restore
-+ * to S0 we must repopulate eSRAM
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
-+ */
-+#ifndef __INTEL_CLN_ESRAM_H__
-+#define __INTEL_CLN_ESRAM_H__
-+
-+#include <linux/module.h>
-+
-+/* Basic size of an eSRAM page */
-+#define INTEL_CLN_ESRAM_PAGE_SIZE (0x1000)
-+#define INTEL_CLN_ESRAM_PAGE_COUNT (0x80)
-+/**
-+ * intel_cln_esram_map_range
-+ *
-+ * @param vaddr: Virtual address to start mapping (must be 4k aligned)
-+ * @param size: Size to map from
-+ * @param mapname: Mapping name
-+ * @return 0 success < 0 failure
-+ *
-+ * Map 4k increments at given address to eSRAM.
-+ */
-+int intel_cln_esram_map_range(void * vaddr, u32 size, char * mapname);
-+
-+/**
-+ * intel_cln_esram_unmap_range
-+ *
-+ * @param vaddr: The virtual address to unmap
-+ * @return 0 success < 0 failure
-+ *
-+ * Logical corollary of esram_map_page
-+ */
-+int intel_cln_esram_unmap_range(void * vaddr, u32 size, char * mapname);
-+
-+/**
-+ * intel_cln_esram_map_symbol
-+ *
-+ * @param vaddr: Virtual address of the symbol
-+ * @return 0 success < 0 failure
-+ *
-+ * Maps a series of 4k chunks starting at vaddr&0xFFFFF000. vaddr shall be a
-+ * kernel text section symbol (kernel or loaded module)
-+ *
-+ * We get the size of the symbol from kallsyms. We guarantee to map the entire
-+ * size of the symbol - plus whatever padding is necessary to get alignment to
-+ * eSRAM_PAGE_SIZE
-+ * Other stuff inside the mapped pages will get a performance boost 'for free'.
-+ * If this free boost is not what you want then
-+ * 1. Align to 4k
-+ * 2. Pad to 4k
-+ * 3. Call intel_cln_esram_map_range()
-+ */
-+int intel_cln_esram_map_symbol(void * vaddr);
-+
-+/**
-+ * intel_cln_esram_unmap_symbol
-+ *
-+ * @param vaddr: Virtual address of the symbol
-+ * @return 0 success < 0 failure
-+ *
-+ * Logical corollary to intel_cln_esram_map_symbol
-+ * Undoes any mapping of pages starting at sym for sym's size
-+ */
-+int intel_cln_esram_unmap_symbol(void * vaddr);
-+
-+#endif /* __INTEL_CLN_ESRAM_H__ */
-diff --git a/drivers/platform/x86/quark/intel_cln_esram_test.c b/drivers/platform/x86/quark/intel_cln_esram_test.c
-new file mode 100644
-index 0000000..3d0573d
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_esram_test.c
-@@ -0,0 +1,602 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/**
-+ * intel_cln_esram_test.c
-+ *
-+ * Simple test module to provide test cases for ITS integration
-+ *
-+ */
-+#include <linux/cdev.h>
-+#include <linux/crc32.h>
-+#include <linux/crc32c.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/fs.h>
-+#include <linux/intel_cln_sb.h>
-+#include <linux/kallsyms.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/slab.h>
-+
-+#include "intel_cln_esram.h"
-+#include "intel_cln_esram_test.h"
-+
-+#define DRIVER_NAME "intel_cln_esram_test"
-+
-+/**
-+ * struct intel_cln_esram_dev
-+ *
-+ * Structre to represent module state/data/etc
-+ */
-+struct intel_cln_esram_test_dev{
-+ unsigned int opened;
-+ struct platform_device *pldev; /* Platform device */
-+ struct cdev cdev;
-+ struct mutex open_lock;
-+ char * pdata;
-+ u32 size;
-+};
-+
-+static struct intel_cln_esram_test_dev esram_test_dev;
-+static struct class *esram_test_class;
-+static DEFINE_MUTEX(esram_test_mutex);
-+static int esram_test_major;
-+static char * name = "testmap";
-+
-+/******************************************************************************
-+ * eSRAM BIST
-+ ******************************************************************************/
-+
-+static int crc_cache = 0;
-+
-+unsigned long long tsc_delta(unsigned long long first, unsigned long long end)
-+{
-+ if (first < end)
-+ return end - first;
-+ else
-+ return (ULLONG_MAX - first) + end;
-+}
-+
-+
-+/**
-+ * intel_cln_crctest
-+ *
-+ * Do a CRC32 of the specified region. Return the time taken in jiffies
-+ */
-+static unsigned long long intel_cln_crctest(char * pdata, u32 crcsize)
-+{
-+ unsigned long long j1 = 0, j2 = 0;
-+
-+ rdtscll(j1);
-+
-+ /* Flush LMT cache to introduce cache miss to our test */
-+ __asm__ __volatile__("wbinvd\n");
-+ crc32(0, pdata, crcsize);
-+
-+ rdtscll(j2);
-+
-+ return tsc_delta(j1, j2);
-+}
-+
-+#ifdef __DEBUG__
-+#define bist_err(x){\
-+ pr_err("eSRAM bist err line %d errno %d\n", (__LINE__-2), x);\
-+ return x;\
-+}
-+#else
-+#define bist_err(x){\
-+ return x;\
-+}
-+#endif
-+/**
-+ * intel_cln_esram_perpage_overlay
-+ *
-+ * Maps to integration test spec ID CLN.F.SW.APP.eSRAM.0
-+ */
-+int intel_cln_esram_test_perpage_overlay(void)
-+{
-+
-+ int ret = 0;
-+ u32 idx = 0, size = INTEL_CLN_ESRAM_PAGE_SIZE;
-+
-+ /* Set a known state */
-+ for(idx = 0; idx < size; idx += sizeof(u32)){
-+ *((u32*)&esram_test_dev.pdata[idx]) = idx;
-+ }
-+
-+
-+ /* Basic test of full range of memory */
-+ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+ for(idx = 0; idx < size; idx += sizeof(u32)){
-+ if(*((u32*)&esram_test_dev.pdata[idx]) != idx){
-+ pr_err("Entry %d is 0x%08x require 0x%08x",
-+ idx, esram_test_dev.pdata[idx], idx);
-+ bist_err(-EIO);
-+ }
-+ }
-+
-+#if 0
-+ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_esram_test_pageref_count
-+ *
-+ * Ensure page reference couting works as expected
-+ */
-+int intel_cln_esram_test_pagref_count(void)
-+{
-+ u32 size = INTEL_CLN_ESRAM_PAGE_SIZE;
-+ int ret = 0;
-+
-+ return 0;
-+ /* Map a page */
-+ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+
-+ /* Map a second time - and verify mapping fails */
-+ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
-+ if(ret == 0){
-+ bist_err(-EFAULT);
-+ }
-+
-+#if 0
-+ /* Unmap - OK */
-+ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+
-+ /* Verify second unmap operation fails */
-+ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
-+ if(ret == 0){
-+ bist_err(-EFAULT);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+extern uint32_t get_crc32table_le(void);
-+
-+/**
-+ * intel_cln_esram_test_contig_perfmetric
-+ *
-+ * Do a CRC16 for a contigous area of memory
-+ * Map contigous area and get a CRC16
-+ *
-+ * Ensure overlayed data takes less time than regular unoverlayed DRAM
-+ */
-+int intel_cln_esram_test_contig_perfmetric(void)
-+{
-+ u32 crcsize = 0x60000;
-+ unsigned long long crc32_fullmap = 0, crc32_fullunmap = 0;
-+ uint32_t crc32table_le = kallsyms_lookup_name("crc32table_le");
-+ int ret = 0;
-+
-+ if (crc32table_le == 0){
-+ pr_err("%s unable to fine symbol crc32table_le\n", __func__);
-+ return -ENODEV;
-+ }
-+
-+ /* Get raw data metric */
-+ crc_cache = 1;
-+ crc32_fullunmap = intel_cln_crctest(esram_test_dev.pdata, crcsize);
-+
-+ /* Map CRC16 symbol (algorithm) + code (data) */
-+ ret = intel_cln_esram_map_symbol(crc32_le);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+ ret = intel_cln_esram_map_symbol((void*)crc32table_le);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+
-+ /* Map test data */
-+ ret = intel_cln_esram_map_range(esram_test_dev.pdata, crcsize, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+
-+ /* Get metric */
-+ crc_cache = 1;
-+ crc32_fullmap = intel_cln_crctest(esram_test_dev.pdata, crcsize);
-+#if 0
-+ /* Tidy up */
-+ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, crcsize, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+ ret = intel_cln_esram_unmap_range(((void*)crc32_table),
-+ sizeof(crc32_table), name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+ ret = intel_cln_esram_unmap_symbol(crc32);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+#endif
-+ pr_info("%s did crctest - mapped - in %llu ticks\n", __func__, crc32_fullmap);
-+ pr_info("%s mapped count %llu unmapped %llu\n",
-+ __func__, crc32_fullmap, crc32_fullunmap);
-+ return crc32_fullmap < crc32_fullunmap;
-+}
-+
-+/**
-+ * intel_cln_esram_test_kernel_codemap
-+ *
-+ * Maps some kernel code - a data section and then calls the code contained
-+ * therein. Proves out the running overlayed eSRAM works
-+ */
-+int intel_cln_esram_test_kernel_codemap(void)
-+{
-+#if 0
-+ int ret = intel_cln_esram_map_symbol(msleep);
-+ if(ret){
-+ printk(KERN_ERR "%s map symbol msleep fail\n", __FUNCTION__);
-+ bist_err(ret);
-+ }
-+
-+ /* run the mapped code */
-+ msleep(1);
-+
-+ /* unmap */
-+ ret = intel_cln_esram_unmap_symbol(msleep);
-+ if(ret){
-+ printk(KERN_ERR "%s unmap symbol msleep fail\n", __FUNCTION__);
-+ bist_err(ret);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_esram_test_kernel_datamap
-+ *
-+ * Tests mapping/unmapping of a kernel data structure
-+ */
-+int intel_cln_esram_test_kernel_datamap(void)
-+{
-+#if 0
-+ unsigned long jtag = 0;
-+ unsigned long ctrl = 0;
-+
-+ /* Map the interrupt descriptor table */
-+ int ret = intel_cln_esram_map_range(idt_table, INTEL_CLN_ESRAM_PAGE_SIZE, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+
-+ jtag = jiffies;
-+ /* Wait for jiffies to tick or timeout to occur (failure) */
-+ while(jtag == jiffies){
-+ ctrl++;
-+ }
-+
-+ /* unmap */
-+ ret = intel_cln_esram_unmap_range(idt_table, INTEL_CLN_ESRAM_PAGE_SIZE, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_esram_test_sub_unsub
-+ *
-+ * Subscribe and unsubscribe 100% of available eSRAM
-+ */
-+int intel_cln_esram_test_sub_unsub(void)
-+{
-+ int ret = 0;
-+ u32 idx = 0, size = INTEL_CLN_ESRAM_PAGE_SIZE * INTEL_CLN_ESRAM_PAGE_COUNT;
-+
-+ /* Set a known state */
-+ for(idx = 0; idx < size; idx += sizeof(u32)){
-+ *((u32*)&esram_test_dev.pdata[idx]) = idx;
-+ }
-+
-+ /* Basic test of full range of memory */
-+ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+ for(idx = 0; idx < size; idx += sizeof(u32)){
-+ if(*((u32*)&esram_test_dev.pdata[idx]) != idx){
-+ pr_err("Entry %d is 0x%08x require 0x%08x",
-+ idx, esram_test_dev.pdata[idx], idx);
-+ bist_err(-EIO);
-+ }
-+ }
-+#if 0
-+ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
-+ if(ret){
-+ bist_err(ret);
-+ }
-+#endif
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_esram_test_over_sub
-+ *
-+ * Test oversubscription of eSRAM
-+ */
-+int intel_cln_esram_test_over_sub(void)
-+{
-+ int ret = 0;
-+ u32 size = INTEL_CLN_ESRAM_PAGE_SIZE * (INTEL_CLN_ESRAM_PAGE_COUNT + 1);
-+
-+ /* Over subscribe should fail */
-+ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
-+ if(ret == 0){
-+ //intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
-+ bist_err(-EFAULT);
-+ }
-+ return 0;
-+}
-+
-+/*
-+ * File ops
-+ */
-+static long esram_test_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ int ret = -EINVAL;
-+
-+ cmd -= CLN_ESRAM_IOCTL_BASE;
-+ switch (cmd) {
-+ case CLN_F_SW_APP_ESRAM_0:
-+ /* Per page overlay */
-+ ret = intel_cln_esram_test_perpage_overlay();
-+ break;
-+
-+ case CLN_F_SW_APP_ESRAM_1:
-+ /* Verify page reference counting */
-+ ret = intel_cln_esram_test_pagref_count();
-+ break;
-+
-+ case CLN_F_SW_APP_ESRAM_2:
-+ /* Performance metric or overlay contig RAM */
-+ ret = intel_cln_esram_test_contig_perfmetric();
-+ if (ret == 1)
-+ ret = 0;
-+ break;
-+
-+ case CLN_F_SW_APP_ESRAM_3:
-+ /* Verify mapping of kernel code section */
-+ /* Covered by test #2 */
-+ ret = 0; //intel_cln_esram_test_kernel_codemap();
-+ break;
-+
-+ case CLN_F_SW_APP_ESRAM_4:
-+ /* Verify mapping of kernel data section (IDT) */
-+ /* Covered by test #2 */
-+ ret = 0; //intel_cln_esram_test_kernel_datamap();
-+ break;
-+
-+ case CLN_F_SW_APP_ESRAM_5:
-+ /* Complete subscribe/unsubscribe eSRAM */
-+ ret = intel_cln_esram_test_sub_unsub();
-+ break;
-+
-+ case CLN_F_SW_APP_ESRAM_6:
-+ /* Over subscribe eSRAM */
-+ ret = intel_cln_esram_test_over_sub();
-+ break;
-+
-+ default:
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int esram_test_open(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&esram_test_mutex);
-+ nonseekable_open(inode, file);
-+
-+ if (mutex_lock_interruptible(&esram_test_dev.open_lock)) {
-+ mutex_unlock(&esram_test_mutex);
-+ return -ERESTARTSYS;
-+ }
-+
-+ if (esram_test_dev.opened) {
-+ mutex_unlock(&esram_test_dev.open_lock);
-+ mutex_unlock(&esram_test_mutex);
-+ return -EINVAL;
-+ }
-+
-+ esram_test_dev.opened++;
-+ mutex_unlock(&esram_test_dev.open_lock);
-+ mutex_unlock(&esram_test_mutex);
-+
-+ return 0;
-+}
-+
-+static int esram_test_release(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&esram_test_dev.open_lock);
-+ esram_test_dev.opened = 0;
-+ mutex_unlock(&esram_test_dev.open_lock);
-+
-+ return 0;
-+}
-+
-+static const struct file_operations esram_test_file_ops = {
-+ .open = esram_test_open,
-+ .release = esram_test_release,
-+ .unlocked_ioctl = esram_test_ioctl,
-+ .llseek = no_llseek,
-+};
-+
-+
-+/**
-+ * intel_cln_esram_test_probe
-+ *
-+ * @param pdev: Platform device
-+ * @return 0 success < 0 failure
-+ *
-+ * Callback from platform sub-system to probe
-+ *
-+ * This driver manages eSRAM on a per-page basis. Therefore if we find block
-+ * mode is enabled, or any global, block-level or page-level locks are in place
-+ * at module initialisation time - we bail out.
-+ */
-+static int intel_cln_esram_test_probe(struct platform_device * pdev)
-+{
-+ int retval = 0;
-+ unsigned int minor = 0;
-+
-+ esram_test_dev.size = INTEL_CLN_ESRAM_PAGE_COUNT * INTEL_CLN_ESRAM_PAGE_SIZE;
-+
-+ /* Get memory */
-+ esram_test_dev.pdata = kzalloc(esram_test_dev.size, GFP_KERNEL);
-+ if(unlikely(esram_test_dev.pdata == NULL)){
-+ pr_err("Can't allocate %d bytes\n", esram_test_dev.size);
-+ return -ENOMEM;
-+ }
-+
-+ mutex_init(&esram_test_dev.open_lock);
-+ cdev_init(&esram_test_dev.cdev, &esram_test_file_ops);
-+ esram_test_dev.cdev.owner = THIS_MODULE;
-+
-+ retval = cdev_add(&esram_test_dev.cdev, MKDEV(esram_test_major, minor), 1);
-+ if (retval) {
-+ printk(KERN_ERR "chardev registration failed\n");
-+ kfree(esram_test_dev.pdata);
-+ return -EINVAL;
-+ }
-+ if (IS_ERR(device_create(esram_test_class, NULL,
-+ MKDEV(esram_test_major, minor), NULL,
-+ "esramtest%u", minor))){
-+ dev_err(&pdev->dev, "can't create device\n");
-+ kfree(esram_test_dev.pdata);
-+ return -EINVAL;
-+ }
-+ printk(KERN_INFO "%s/%s/%s complete OK !!\n", __FUNCTION__, __DATE__,__TIME__);
-+ return 0;
-+
-+}
-+
-+/**
-+ * intel_cln_esram_remove
-+ *
-+ * @return 0 success < 0 failure
-+ *
-+ * Removes a platform device
-+ */
-+static int intel_cln_esram_test_remove(struct platform_device * pdev)
-+{
-+ unsigned int minor = MINOR(esram_test_dev.cdev.dev);
-+
-+ device_destroy(esram_test_class, MKDEV(esram_test_major, minor));
-+ cdev_del(&esram_test_dev.cdev);
-+ kfree(esram_test_dev.pdata);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Platform structures useful for interface to PM subsystem
-+ */
-+static struct platform_driver intel_cln_esram_test_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .remove = intel_cln_esram_test_remove,
-+};
-+
-+/**
-+ * intel_cln_esram_init
-+ *
-+ * @return 0 success < 0 failure
-+ *
-+ * Module entry point
-+ */
-+static int __init intel_cln_esram_test_init(void)
-+{
-+ int retval = 0;
-+ dev_t dev;
-+
-+ esram_test_class = class_create(THIS_MODULE,"cln_esram_test");
-+ if (IS_ERR(esram_test_class)) {
-+ retval = PTR_ERR(esram_test_class);
-+ printk(KERN_ERR "esram_test: can't register earam_test class\n");
-+ goto err;
-+ }
-+
-+ retval = alloc_chrdev_region(&dev, 0, 1, "esram_test");
-+ if (retval) {
-+ printk(KERN_ERR "earam_test: can't register character device\n");
-+ goto err_class;
-+ }
-+ esram_test_major = MAJOR(dev);
-+
-+ memset(&esram_test_dev, 0x00, sizeof(esram_test_dev));
-+ esram_test_dev.pldev = platform_create_bundle(
-+ &intel_cln_esram_test_driver, intel_cln_esram_test_probe, NULL, 0, NULL, 0);
-+
-+ if(IS_ERR(esram_test_dev.pldev)){
-+ printk(KERN_ERR "platform_create_bundle fail!\n");
-+ retval = PTR_ERR(esram_test_dev.pldev);
-+ goto err_class;
-+ }
-+
-+ return 0;
-+
-+err_class:
-+ class_destroy(esram_test_class);
-+err:
-+ return retval;
-+}
-+
-+/**
-+ * intel_cln_esram_exit
-+ *
-+ * Module exit
-+ */
-+static void __exit intel_cln_esram_test_exit(void)
-+{
-+ platform_device_unregister(esram_test_dev.pldev);
-+ platform_driver_unregister(&intel_cln_esram_test_driver);
-+}
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
-+MODULE_DESCRIPTION("Intel Clanton eSRAM ITS driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+module_init(intel_cln_esram_test_init);
-+module_exit(intel_cln_esram_test_exit);
-diff --git a/drivers/platform/x86/quark/intel_cln_esram_test.h b/drivers/platform/x86/quark/intel_cln_esram_test.h
-new file mode 100644
-index 0000000..98e4546
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_esram_test.h
-@@ -0,0 +1,43 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/**
-+ * intel_cln_esram_test.h
-+ *
-+ * Define integers for ioctl operation
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
-+ */
-+
-+#ifndef __INTEL_CLN_ESRAM_TEST_H__
-+#define __INTEL_CLN_ESRAM_TEST_H__
-+
-+#define CLN_ESRAM_IOCTL_BASE 255
-+#define CLN_F_SW_APP_ESRAM_0 0x00000000
-+#define CLN_F_SW_APP_ESRAM_1 0x00000001
-+#define CLN_F_SW_APP_ESRAM_2 0x00000002
-+#define CLN_F_SW_APP_ESRAM_3 0x00000003
-+#define CLN_F_SW_APP_ESRAM_4 0x00000004
-+#define CLN_F_SW_APP_ESRAM_5 0x00000005
-+#define CLN_F_SW_APP_ESRAM_6 0x00000006
-+#define CLN_F_SW_APP_ESRAM_7 0x00000007
-+#define CLN_F_SW_APP_ESRAM_8 0x00000008
-+
-+#endif /* __INTEL_CLN_ESRAM_TEST_H__ */
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_imr.c b/drivers/platform/x86/quark/intel_cln_imr.c
-new file mode 100644
-index 0000000..b8259a6
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_imr.c
-@@ -0,0 +1,584 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton IMR driver
-+ *
-+ * IMR stand for Insolate Memory Region, supported by Clanton SoC.
-+ *
-+ * A total number of 8 IMRs have implemented by Clanton SoC,
-+ * Some IMRs might be already occupied by BIOS or Linux during
-+ * booting time.
-+ *
-+ * A user can cat /sys/devices/platform/intel-cln-imr/status for current IMR
-+ * status
-+ *
-+ * To allocate an IMR addresses must be alinged to 1k
-+ *
-+ * The IMR alloc API will locate the next available IMR slot set up
-+ * with input memory region, then apply the input access right masks
-+ *
-+ * The IMR can be freed with the pre-allocated memory addresses.
-+ */
-+
-+#include <asm-generic/uaccess.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/proc_fs.h>
-+
-+#include "intel_cln_imr.h"
-+#include <asm/imr.h>
-+
-+#define DRIVER_NAME "intel-cln-imr"
-+
-+#define IMR_READ_MASK 0x1
-+#define IMR_MAX_ID 7
-+
-+#ifndef phys_to_virt
-+#define phys_to_virt __va
-+#endif
-+
-+/* IMR HW register address structre */
-+struct cln_imr_reg_t {
-+ u8 imr_xl; /* high address register */
-+ u8 imr_xh; /* low address register */
-+ u8 imr_rm; /* read mask register */
-+ u8 imr_wm; /* write mask register */
-+} cln_imr_reg_t;
-+
-+/**
-+ * struct cln_imr_addr_t
-+ *
-+ * IMR memory address structure
-+ */
-+struct cln_imr_addr_t {
-+ u32 addr_low; /* low boundary memroy address */
-+ u32 addr_high; /* high boundary memory address */
-+ u32 read_mask; /* read access right mask */
-+ u32 write_mask; /* write access right mask */
-+} cln_imr_addr_t;
-+
-+/**
-+ * struct cln_imr_pack
-+ *
-+ * local IMR pack structure
-+ */
-+struct cln_imr_pack {
-+ bool occupied; /* IMR occupied */
-+ bool locked; /* IMR lock */
-+ struct cln_imr_reg_t reg; /* predefined imr register address */
-+ struct cln_imr_addr_t addr; /* IMR address region structure */
-+ unsigned char info[MAX_INFO_SIZE]; /* IMR info */
-+} cln_imr_pack;
-+
-+
-+/* Predefined HW register address */
-+static struct cln_imr_reg_t imr_reg_value[] = {
-+ { IMR0L, IMR0H, IMR0RM, IMR0WM },
-+ { IMR1L, IMR1H, IMR1RM, IMR1WM },
-+ { IMR2L, IMR2H, IMR2RM, IMR2WM },
-+ { IMR3L, IMR3H, IMR3RM, IMR3WM },
-+ { IMR4L, IMR4H, IMR4RM, IMR4WM },
-+ { IMR5L, IMR5H, IMR5RM, IMR5WM },
-+ { IMR6L, IMR6H, IMR6RM, IMR6WM },
-+ { IMR7L, IMR7H, IMR7RM, IMR7WM }
-+};
-+
-+static struct platform_device *pdev;
-+
-+/**
-+ * module parameter
-+ * IMR slot should repersant the available IMR region from
-+ * linux boot and BIOS.
-+ *
-+ * For example: imr_bit_mask = 0x10111001
-+ * occupied IMR: 0, 3, 4, 5, 7
-+ * un-occupied IMR: 1, 2, 6
-+ */
-+static int imr_bit_mask = 0xFF;
-+module_param(imr_bit_mask, int, S_IRUGO|S_IWUSR);
-+MODULE_PARM_DESC(imr_bit_mask, "IMR bit mask");
-+
-+/**
-+ * module parameter
-+ * if IMR lock is a nozero value, all unlocked
-+ * imrs will be locked regardless the usage.
-+ */
-+static int imr_lock = 0;
-+module_param(imr_lock, int, S_IRUGO|S_IWUSR);
-+MODULE_PARM_DESC(imr_lock, "switch to lock unused IMR");
-+
-+/* local IMR data structure */
-+struct cln_imr_pack local_imr[IMR_MAXID];
-+
-+/**
-+ * intel_cln_imr_read_reg
-+ *
-+ * @param reg: register address
-+ * @return nothing
-+ *
-+ * return register value from input address.
-+ */
-+static inline uint32_t intel_cln_imr_read_reg(uint8_t reg)
-+{
-+ uint32_t temp = 0;
-+
-+ intel_cln_sb_read_reg(SB_ID_ESRAM, CFG_READ_OPCODE, reg, &temp, 0);
-+ return temp;
-+}
-+
-+/**
-+ * intel_clm_imr_latch_data
-+ *
-+ * @return nothing
-+ *
-+ * Populate IMR data structure from HW.
-+ */
-+static inline void intel_clm_imr_latch_data(void)
-+{
-+ int i = 0;
-+
-+ for (i = 0; i < IMR_MAXID; i++) {
-+
-+ local_imr[i].addr.addr_low =
-+ intel_cln_imr_read_reg(imr_reg_value[i].imr_xl);
-+ local_imr[i].addr.addr_high =
-+ intel_cln_imr_read_reg(imr_reg_value[i].imr_xh);
-+ local_imr[i].addr.read_mask =
-+ intel_cln_imr_read_reg(imr_reg_value[i].imr_rm);
-+ local_imr[i].addr.write_mask =
-+ intel_cln_imr_read_reg(imr_reg_value[i].imr_wm);
-+
-+ if (local_imr[i].addr.addr_low & IMR_LOCK_BIT)
-+ local_imr[i].locked = true;
-+
-+ if (local_imr[i].addr.read_mask > 0 &&
-+ local_imr[i].addr.read_mask < IMR_READ_ENABLE_ALL){
-+ local_imr[i].occupied = true;
-+ } else {
-+ local_imr[i].occupied = false;
-+ memcpy(local_imr[i].info, "NOT USED", MAX_INFO_SIZE);
-+ }
-+ }
-+}
-+
-+/**
-+ * prepare_input_addr
-+ *
-+ * @param addr: input physical memory address
-+ * @return formated memory address
-+ *
-+ * 1. verify input memory address alignment
-+ * 2. apply IMR_REG_MASK to match the format required by HW
-+ */
-+static inline uint32_t prepare_input_addr(uint32_t addr)
-+{
-+ if (addr & (IMR_MEM_ALIGN - 1))
-+ return 0;
-+
-+ addr = (addr >> 8) & IMR_REG_MASK;
-+ return addr;
-+}
-+
-+/**
-+ * intel_cln_imr_find_free_entry
-+ *
-+ * @return the next free imr slot
-+ */
-+static int intel_cln_imr_find_free_entry(void)
-+{
-+ int i = 0;
-+
-+ intel_clm_imr_latch_data();
-+
-+ for (i = 0; i < IMR_MAXID; i++) {
-+ if ((!local_imr[i].occupied) && (!local_imr[i].locked))
-+ return i;
-+ }
-+
-+ pr_err("%s: No more free IMR available.\n", __func__);
-+ return -ENOMEM;
-+}
-+
-+/**
-+ * intel_cln_imr_add_entry
-+ *
-+ * @param id: imr slot id
-+ * @param hi: hi memory address
-+ * @param lo: lo memory address
-+ * @param read: read access mask
-+ * @param write: write access mask
-+ * @return nothing
-+ *
-+ * Setup an IMR entry
-+ */
-+static void intel_cln_imr_add_entry(int id, uint32_t hi,
-+ uint32_t lo, uint32_t read, uint32_t write, bool lock)
-+{
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_xl, lo, 0);
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_xh, hi, 0);
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_rm, read, 0);
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_wm, write, 0);
-+ if (lock) {
-+ lo |= IMR_LOCK_BIT;
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_xl, lo, 0);
-+ }
-+}
-+
-+/**
-+ * get_phy_addr
-+ * @return phy address value
-+ *
-+ * convert register format to physical address format.
-+ */
-+static uint32_t get_phy_addr(uint32_t reg_value)
-+{
-+ reg_value = ((reg_value & IMR_REG_MASK) << 8);
-+ return reg_value;
-+}
-+
-+
-+
-+/**
-+ * intel_cln_imr_init_mask
-+ *
-+ * @param mask: module parameter
-+ * @return nothing
-+ *
-+ * prepare local IMR data structure from input module parameter.
-+ */
-+static void intel_cln_imr_init_mask(int mask)
-+{
-+ int i = 0;
-+
-+ BUG_ON((mask > 255 || mask < 0));
-+
-+ for (i = 0; i < IMR_MAXID; i++) {
-+ local_imr[i].addr.addr_low =
-+ intel_cln_imr_read_reg(imr_reg_value[i].imr_xl);
-+
-+ /* mask bit 1 means imr occupied*/
-+ if (((mask>>i) & IMR_READ_MASK) == 0) {
-+ if (!(local_imr[i].addr.addr_low & IMR_LOCK_BIT))
-+ intel_cln_remove_imr_entry(i);
-+ }
-+ }
-+}
-+
-+/**
-+ * intel_cln_remove_imr_entry
-+ *
-+ * @param id: imr slot id
-+ * @return nothing
-+ *
-+ * remove imr slot based on input id
-+ */
-+void intel_cln_remove_imr_entry(int id)
-+{
-+ if (id >= IMR_MAXID || local_imr[id].locked)
-+ return;
-+
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_rm, IMR_READ_ENABLE_ALL,
-+ 0);
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_wm, IMR_WRITE_ENABLE_ALL,
-+ 0);
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_xl, IMR_BASE_ADDR, 0);
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ imr_reg_value[id].imr_xh, IMR_BASE_ADDR, 0);
-+
-+ intel_clm_imr_latch_data();
-+
-+}
-+EXPORT_SYMBOL(intel_cln_remove_imr_entry);
-+
-+/**
-+ * intel_cln_imr_alloc
-+ *
-+ * @param high: high boundary of memory address
-+ * @param low: low boundary of memorry address
-+ * @param read: IMR read mask value
-+ * @param write: IMR write mask value
-+ * @return nothing
-+ *
-+ * setup the next available IMR with customized read and write masks
-+ */
-+int intel_cln_imr_alloc(uint32_t high, uint32_t low, uint32_t read,
-+ uint32_t write, unsigned char *info, bool lock)
-+{
-+ int id = 0;
-+
-+ if (info == NULL)
-+ return -EINVAL;
-+
-+ if ((low & IMR_LOCK_BIT) || (read == 0 || write == 0)) {
-+ pr_err("%s: Invalid acces mode\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ /* Calculate aligned addresses and validate range */
-+ high = prepare_input_addr(high);
-+ low = prepare_input_addr(low);
-+
-+ /* Find a free entry */
-+ id = intel_cln_imr_find_free_entry();
-+ if (id < 0)
-+ return -ENOMEM;
-+
-+ /* Add entry - locking as necessary */
-+ intel_cln_imr_add_entry(id, high, low, (read & IMR_READ_ENABLE_ALL),
-+ write, lock);
-+
-+ /* Name the new entry */
-+ memcpy(local_imr[id].info, info, MAX_INFO_SIZE);
-+
-+ /* Update local data structures */
-+ intel_clm_imr_latch_data();
-+
-+ pr_info("IMR alloc id %d 0x%08x - 0x%08x %s\n", id, low, high,
-+ lock ? "locked" : "unlocked");
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_imr_alloc);
-+
-+/**
-+ * intel_cln_imr_free
-+ *
-+ * @param high: high boundary of memory address
-+ * @param low: low boundary of memorry address
-+ * @return nothing
-+ *
-+ * remove the imr based on input memory region
-+ */
-+int intel_cln_imr_free(uint32_t high, uint32_t low)
-+{
-+ int i = 0;
-+
-+ if (low > high) {
-+ pr_err("%s: Invalid input address values.\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ high = prepare_input_addr(high);
-+ if (!high) {
-+ pr_err("%s: Invalid input memory address.\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ low = prepare_input_addr(low);
-+ if (!low) {
-+ pr_err("%s: Invalid input memory address.\n", __func__);
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < IMR_MAXID; i++) {
-+ if (local_imr[i].occupied
-+ && (local_imr[i].addr.addr_low == low)
-+ && (local_imr[i].addr.addr_high == high)
-+ && (!local_imr[i].locked)) {
-+ intel_cln_remove_imr_entry(i);
-+ return 0;
-+ }
-+ }
-+
-+ return -EINVAL;
-+}
-+EXPORT_SYMBOL(intel_cln_imr_free);
-+
-+/**
-+ * intel_cln_imr_init_data
-+ *
-+ * @return nothing
-+ * initialize local_imr data structure
-+ */
-+static void intel_cln_imr_init_data(void)
-+{
-+ int i = 0;
-+ char * res_str = "System Reserved Region";
-+ int len = strlen(res_str);
-+
-+ intel_clm_imr_latch_data();
-+
-+ for (i = 0; i < IMR_MAXID; i++) {
-+ local_imr[i].reg = imr_reg_value[i];
-+ memcpy(local_imr[i].info, res_str, len);
-+ }
-+}
-+
-+/**
-+ * intel_cln_imr_lockall
-+ *
-+ * @param mask: module parameter
-+ * @return nothing
-+ *
-+ * lock up all un-locked IMRs
-+ */
-+int intel_cln_imr_lockall(void)
-+{
-+ int i = 0;
-+ uint32_t temp_addr;
-+
-+ /* Enumerate IMR data structures */
-+ intel_cln_imr_init_data();
-+ intel_cln_imr_init_mask(imr_bit_mask);
-+
-+ /* Cycle through IMRs locking whichever are unlocked */
-+ for (i = 0; i < IMR_MAXID; i++) {
-+
-+ temp_addr = local_imr[i].addr.addr_low;
-+ if (!(temp_addr & IMR_LOCK_BIT)) {
-+
-+ DBG("%s: locking IMR %d\n", __func__, i);
-+ temp_addr |= IMR_LOCK_BIT;
-+ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
-+ local_imr[i].reg.imr_xl,
-+ temp_addr, 0);
-+ }
-+ }
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_imr_lockall);
-+
-+/**
-+ * intel_cln_imr_stat_show
-+ *
-+ * @param dev: pointer to device
-+ * @param attr: attribute pointer
-+ * @param buf: output buffer
-+ * @return number of bytes successfully read
-+ *
-+ * Populates IMR state via /sys/device/intel-cln-imr/stat
-+ */
-+static int intel_cln_imr_stat_show(struct device *dev,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ int len = 0;
-+ int i = 0;
-+ int size, count = PAGE_SIZE;
-+ uint32_t hi_phy_addr, lo_phy_addr;
-+
-+ for (i = 0; i < IMR_MAXID; i++) {
-+
-+ /* read back the actual input physical memory address */
-+ hi_phy_addr = get_phy_addr(local_imr[i].addr.addr_high);
-+ lo_phy_addr = get_phy_addr(local_imr[i].addr.addr_low);
-+
-+ /* the IMR always protect extra 1k memory size above the input
-+ * high reg value
-+ */
-+ size = ((hi_phy_addr - lo_phy_addr) / IMR_MEM_ALIGN) + 1;
-+
-+ size = snprintf(buf+len, count,
-+ "imr - id : %d\n"
-+ "info : %s\n"
-+ "occupied : %s\n"
-+ "locked : %s\n"
-+ "size : %d kb\n"
-+ "hi addr (phy): 0x%08x\n"
-+ "lo addr (phy): 0x%08x\n"
-+ "hi addr (vir): 0x%08x\n"
-+ "lo addr (vir): 0x%08x\n"
-+ "read mask : 0x%08x\n"
-+ "write mask : 0x%08x\n\n",
-+ i,
-+ local_imr[i].info,
-+ local_imr[i].occupied ? "yes" : "no",
-+ local_imr[i].locked ? "yes" : "no",
-+ size,
-+ hi_phy_addr,
-+ lo_phy_addr,
-+ (uint32_t)phys_to_virt(hi_phy_addr),
-+ (uint32_t)phys_to_virt(lo_phy_addr),
-+ local_imr[i].addr.read_mask,
-+ local_imr[i].addr.write_mask);
-+ len += size;
-+ count -= size;
-+ }
-+ return len;
-+}
-+
-+static struct device_attribute dev_attr_stats = {
-+ .attr = {
-+ .name = "stat",
-+ .mode = 0444, },
-+ .show = intel_cln_imr_stat_show,
-+};
-+
-+static struct attribute *platform_attributes[] = {
-+ &dev_attr_stats.attr,
-+ NULL,
-+};
-+
-+static struct attribute_group imr_attrib_group = {
-+ .attrs = platform_attributes
-+};
-+
-+/**
-+ * intel_cln_imr_init
-+ *
-+ * @return 0 success < 0 failue
-+ *
-+ * module entry point
-+ */
-+int __init intel_cln_imr_init(void)
-+{
-+ int ret;
-+
-+ pdev = platform_device_alloc(DRIVER_NAME, -1);
-+ if (!pdev)
-+ return -ENOMEM;
-+
-+ ret = platform_device_add(pdev);
-+ if (ret)
-+ goto fail_platform;
-+
-+ /* initialise local imr data structure */
-+ intel_cln_imr_init_data();
-+
-+ ret = sysfs_create_group(&pdev->dev.kobj, &imr_attrib_group);
-+ if (ret)
-+ goto fail_platform;
-+
-+ if(intel_cln_imr_runt_setparams() == 0 && imr_lock == 1){
-+ intel_cln_imr_lockall();
-+ }
-+
-+ return 0;
-+
-+fail_platform:
-+ platform_device_del(pdev);
-+ return ret;
-+}
-+EXPORT_SYMBOL(intel_cln_imr_init);
-+
-+MODULE_DESCRIPTION("Intel Clanton SOC IMR API ");
-+MODULE_AUTHOR("Intel Corporation");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_imr.h b/drivers/platform/x86/quark/intel_cln_imr.h
-new file mode 100644
-index 0000000..3861d60
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_imr.h
-@@ -0,0 +1,155 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton IMR driver
-+ *
-+ * IMR stand for Insolate Memory Region, supported by Clanton SoC.
-+ *
-+ * A total number of 8 IMRs have implemented by Clanton SoC,
-+ * some IMRs might be already occupied by BIOS or Linux booting time.
-+ *
-+ * Input addresses parameter required the actual Physical address.
-+ *
-+ * The IMR alloc API will locate the next available IMR slot set up
-+ * with input memory region, and apply with the default access right
-+ * (CPU & CPU_snoop enable).
-+ *
-+ * The alloc_mask API takes input read & write masks values to set up
-+ * IMR with customized access right.
-+ *
-+ * User can free IMR with pre-alloc specified addresses.
-+ */
-+
-+#ifndef __INTEL_CLN_IMR_H__
-+#define __INTEL_CLN_IMR_H__
-+
-+#include <linux/intel_cln_sb.h>
-+#include "asm/io.h"
-+
-+#define CFG_READ_OPCODE 0x10 /* BUnit Control Read */
-+#define CFG_WRITE_OPCODE 0x11 /* BUnit control write */
-+
-+/* DRAM IMR register addresses */
-+#define IMR0L 0x40
-+#define IMR0H 0x41
-+#define IMR0RM 0x42
-+#define IMR0WM 0x43
-+#define IMR1L 0x44
-+#define IMR1H 0x45
-+#define IMR1RM 0x46
-+#define IMR1WM 0x47
-+#define IMR2L 0x48
-+#define IMR2H 0x49
-+#define IMR2RM 0x4A
-+#define IMR2WM 0x4B
-+#define IMR3L 0x4C
-+#define IMR3H 0x4D
-+#define IMR3RM 0x4E
-+#define IMR3WM 0x4F
-+#define IMR4L 0x50
-+#define IMR4H 0x51
-+#define IMR4RM 0x52
-+#define IMR4WM 0x53
-+#define IMR5L 0x54
-+#define IMR5H 0x55
-+#define IMR5RM 0x56
-+#define IMR5WM 0x57
-+#define IMR6L 0x58
-+#define IMR6H 0x59
-+#define IMR6RM 0x5A
-+#define IMR6WM 0x5B
-+#define IMR7L 0x5C
-+#define IMR7H 0x5D
-+#define IMR7RM 0x5E
-+#define IMR7WM 0x5F
-+
-+#define IMR_LOCK_BIT 0x80000000
-+#define IMR_WRITE_ENABLE_ALL 0xFFFFFFFF
-+#define IMR_READ_ENABLE_ALL 0xBFFFFFFF
-+#define IMR_REG_MASK 0xFFFFFC
-+
-+#define IMR_ESRAM_FLUSH_INIT 0x80000000 /* esram flush */
-+#define IMR_SNOOP_ENABLE 0x40000000 /* core snoops */
-+#define IMR_PUNIT_ENABLE 0x20000000
-+#define IMR_SMM_ENABLE 0x02 /* core SMM access */
-+#define IMR_NON_SMM_ENABLE 0x01 /* core non-SMM access */
-+#define IMR_BASE_ADDR 0x00
-+#define IMR_MEM_ALIGN 0x400
-+
-+#define MAX_INFO_SIZE 64
-+#define IMR_MAXID 8
-+
-+/* snoop + Non SMM write mask */
-+#define IMR_DEFAULT_MASK (IMR_SNOOP_ENABLE \
-+ + IMR_ESRAM_FLUSH_INIT \
-+ + IMR_NON_SMM_ENABLE)
-+
-+/* debug printk */
-+#ifdef DEBUG
-+#define DBG(args...) pr_info(args)
-+#else
-+#define DBG(args...)
-+#endif
-+
-+extern unsigned long _text;
-+extern unsigned long __init_begin;
-+
-+/**
-+ * intel_cln_imr_alloc
-+ *
-+ * @param high: the end of physical memory address
-+ * @param low: the start of physical memory address
-+ * @param read: IMR read mask value
-+ * @param write: IMR write maks value
-+ * @param info: imr information
-+ * @param lock: imr lock
-+ *
-+ * Setup imr with customised read/ write masks
-+ */
-+int intel_cln_imr_alloc(u32 high, u32 low, u32 read, u32 write,
-+ unsigned char *info, bool lock);
-+
-+/**
-+ * intel_cln_imr_free
-+ *
-+ * @param high: high boundary of memory address
-+ * @param low: low boundary of memorry address
-+ *
-+ * remove the imr based on input memory region
-+ */
-+int intel_cln_imr_free(u32 high, u32 low);
-+
-+/**
-+ * intel_cln_remove_imr_entry
-+ *
-+ * @param id: internal imr data struct id
-+ *
-+ * Remove imr based on input imr data structure id
-+ */
-+void intel_cln_remove_imr_entry(int id);
-+
-+/**
-+ * intel_cln_imr_init
-+ *
-+ * Initialise IMRs
-+ */
-+int intel_cln_imr_init(void);
-+
-+#endif
-diff --git a/drivers/platform/x86/quark/intel_cln_imr_kernel.c b/drivers/platform/x86/quark/intel_cln_imr_kernel.c
-new file mode 100644
-index 0000000..51e8676
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_imr_kernel.c
-@@ -0,0 +1,139 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton IMR driver
-+ *
-+ * IMR stand for Insolate Memory Region, supported by Clanton SoC.
-+ *
-+ * The IMR id 3 is pre-defined as the use for kernel data protection
-+ *
-+ * The early imr protects entire memory (from the beginning of kernel text
-+ * section to the top of memory) during linux boot time. In the linux run
-+ * time, the protection need to resize down to memory region that only
-+ * contains: kernel text, read only data, and initialized data section.
-+ *
-+ */
-+#include <linux/errno.h>
-+#include <linux/intel_cln_sb.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/platform_data/clanton.h>
-+#include <linux/printk.h>
-+#include "intel_cln_imr.h"
-+
-+/* pre-defined imr id for uncompressed kernel */
-+#define IMR_KERNEL_ID 3
-+
-+/**
-+ * addr_hw_ready
-+ *
-+ * shift input address value to match HW required 1k aligned format
-+ */
-+static inline uint32_t addr_hw_ready(uint32_t addr)
-+{
-+ /* memory alignment */
-+ addr &= (~((1 << 10) - 1));
-+
-+ /* prepare input addr in HW required format */
-+ addr = (addr >> 8) & IMR_REG_MASK;
-+ return addr;
-+}
-+
-+/**
-+ * void intel_cln_imr_runt_kerndata_setup
-+ *
-+ * Setup imr for kernel text, read only data section
-+ *
-+ * The read only data (rodata) section placed between text and initialized data
-+ * section by kernel.
-+ */
-+static void intel_cln_imr_runt_kerndata_setup(void)
-+{
-+ uint32_t hi;
-+ uint32_t lo;
-+
-+ hi = (uint32_t)virt_to_phys(&__init_begin);
-+ lo = (uint32_t)virt_to_phys(&_text);
-+
-+ /* Set a locked IMR around the kernel .text section */
-+ if (intel_cln_imr_alloc((hi - IMR_MEM_ALIGN), lo,
-+ IMR_DEFAULT_MASK, IMR_DEFAULT_MASK,
-+ "KERNEL RUNTIME DATA", 1)) {
-+ pr_err("IMR: Set up runtime kernel data imr faild!\n");
-+ return;
-+ }
-+}
-+
-+/**
-+ * intel_cln_imr_teardown_unlocked
-+ *
-+ * Remove any unlocked IMR
-+ *
-+ */
-+static void intel_cln_imr_teardown_unlocked(void)
-+{
-+ int i = 0;
-+ for (i = 0; i < IMR_MAXID; i++)
-+ intel_cln_remove_imr_entry(i);
-+}
-+
-+/**
-+ * intel_cln_imr_runt_setparams
-+ *
-+ * set imr range for text, read only, initialised data in linux run time
-+ */
-+int intel_cln_imr_runt_setparams(void)
-+{
-+ /* Setup an IMR around the kernel .text area */
-+ intel_cln_imr_runt_kerndata_setup();
-+
-+ /* Remove any other unlocked IMR */
-+ intel_cln_imr_teardown_unlocked();
-+
-+ return 0;
-+}
-+EXPORT_SYMBOL(intel_cln_imr_runt_setparams);
-+
-+/**
-+ * intel_cln_imr_runt_init
-+ *
-+ * module entry point
-+ */
-+static int __init intel_cln_imr_runt_init(void)
-+{
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_imr_runt_exit
-+ *
-+ * Module exit
-+ */
-+static void __exit intel_cln_imr_runt_exit(void)
-+{
-+ /* do nothing */
-+}
-+
-+MODULE_DESCRIPTION("Intel Clanton SOC IMR API ");
-+MODULE_AUTHOR("Intel Corporation");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+subsys_initcall(intel_cln_imr_runt_init);
-+module_exit(intel_cln_imr_runt_exit);
-diff --git a/drivers/platform/x86/quark/intel_cln_imr_test.c b/drivers/platform/x86/quark/intel_cln_imr_test.c
-new file mode 100644
-index 0000000..2d98507
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_imr_test.c
-@@ -0,0 +1,357 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton IMR Test module
-+ *
-+ */
-+
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/fs.h>
-+#include <linux/intel_cln_sb.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/slab.h>
-+#include "intel_cln_imr.h"
-+
-+#define DRIVER_NAME "intel_cln_imr_test"
-+
-+/**
-+ * XXX intel_cln_sb.h needs to be updated with SB_ID_PUNIT and change
-+ * propagated. This is a workaround to make it look less ugly. */
-+#define SB_ID_PUNIT SB_ID_THERMAL
-+
-+/* Memory-mapped SPI Flash address */
-+#define ILB_SPIFLASH_BASEADDR 0xFF800000
-+/* PUnit DMA block transfer size, in bytes */
-+#define SPI_DMA_BLOCK_SIZE 512
-+
-+/**************************** Exported to LISA *******************************/
-+
-+/*
-+ * Internally-used ioctl code. At the moment it is not reserved by any mainline
-+ * driver.
-+ */
-+#define IMR_TEST_IOCTL_CODE 0xE1
-+
-+/*
-+ * Integers for ioctl operation.
-+ */
-+#define IOCTL_CLN_SANITY_CHECK_PUNIT_DMA _IO(IMR_TEST_IOCTL_CODE, 0x00)
-+#define IOCTL_CLN_IMR_1 _IO(IMR_TEST_IOCTL_CODE, 0x01)
-+
-+/*****************************************************************************/
-+
-+/**
-+ * struct intel_cln_imr_dev
-+ *
-+ * Structure to represent module state/data/etc
-+ */
-+struct intel_cln_imr_test_dev {
-+ unsigned int opened;
-+ struct platform_device *pldev; /* Platform device */
-+ struct cdev cdev;
-+ struct mutex open_lock;
-+};
-+
-+static struct intel_cln_imr_test_dev imr_test_dev;
-+static struct class *imr_test_class;
-+static DEFINE_MUTEX(imr_test_mutex);
-+static int imr_test_major;
-+
-+/* PUnit DMA registers over side-band */
-+#define PUNIT_SPI_DMA_COUNT_REG 0x60
-+#define PUNIT_SPI_DMA_DEST_REG 0x61
-+#define PUNIT_SPI_DMA_SRC_REG 0x62
-+
-+/**
-+ * ilb_spi_dma_read
-+ *
-+ * @param src: physical address in Legacy SPI Flash
-+ * @param dst: physical address of destination
-+ * @param dma_block_count: number of 512B SPI Flash blocks to be transferred
-+ *
-+ * Read-access iLB SPI via PUnit DMA engine.
-+ *
-+ */
-+static void ilb_spi_dma_read(u32 *src, u32 *dst, u32 dma_block_count)
-+{
-+ pr_info("%s: src=%p, dst=%p, count=%u\n", __func__, src, dst,
-+ dma_block_count);
-+
-+ /* Setup source and destination addresses. */
-+ intel_cln_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
-+ PUNIT_SPI_DMA_SRC_REG, (u32) src, 0);
-+ intel_cln_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
-+ PUNIT_SPI_DMA_DEST_REG, (u32) dst, 0);
-+
-+ pr_info("%s: starting transaction\n", __func__);
-+
-+ /*
-+ * Setup the number of block to be copied over. Transaction will start
-+ * as soon as the register is filled with value.
-+ */
-+ intel_cln_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
-+ PUNIT_SPI_DMA_COUNT_REG, dma_block_count, 0);
-+
-+ /* Poll for completion. */
-+ while (dma_block_count > 0) {
-+ intel_cln_sb_read_reg(SB_ID_PUNIT, CFG_READ_OPCODE,
-+ PUNIT_SPI_DMA_COUNT_REG, &dma_block_count, 0);
-+ }
-+
-+ pr_info("%s: transaction completed\n", __func__);
-+}
-+
-+/**
-+ * punit_dma_sanity_check
-+ *
-+ * @return 0 if success, 1 if failure
-+ *
-+ * Perform a basic sanity check for PUnit DMA engine. Copy over a 512B SPI
-+ * Flash block.
-+ */
-+static int punit_dma_sanity_check(void)
-+{
-+ int err = 0;
-+ u32 *buffer = NULL;
-+ u32 buf_ph_addr = 0;
-+
-+ /* Allocate 512B buffer for 1 SPI Flash block */
-+ buffer = kzalloc(SPI_DMA_BLOCK_SIZE, GFP_KERNEL);
-+ if (!buffer) {
-+ err = -ENOMEM;
-+ goto end;
-+ }
-+
-+ /* DMA first SPI Flash block into buffer */
-+ buf_ph_addr = (u32)virt_to_phys(buffer);
-+ ilb_spi_dma_read((u32 *)ILB_SPIFLASH_BASEADDR, (u32 *)buf_ph_addr, 1);
-+
-+ kfree(buffer);
-+end:
-+ return err;
-+}
-+
-+/**
-+ * imr_violate_kernel_punit_dma
-+ *
-+ * @return always 0
-+ *
-+ * PUnit-DMA access to the Uncompressed Kernel IMR.
-+ * This is based on set_imr_kernel_data() in intel_cln_imr.c. Find the physical
-+ * address of .text section and copy a 512B chunk of legacy SPI via PuUnit DMA.
-+ *
-+ */
-+static int imr_violate_kernel_punit_dma(void)
-+{
-+ extern unsigned long _text;
-+ u32 kernel_text = (u32)virt_to_phys(&_text);
-+
-+ /* We expect this to trigger an IMR violation reset */
-+ ilb_spi_dma_read((u32 *)ILB_SPIFLASH_BASEADDR, (u32 *)kernel_text, 1);
-+
-+ /*
-+ * If we're still alive, we have a serious bug:
-+ * - we didn't appropriately target the IMR?
-+ * - if we have, weren't we prevented from accessing?
-+ * - if we weren't prevented, it's unlikely we're alive with a dirty
-+ * text section
-+ */
-+ pr_err("%s: BUG: still running after DMAing into kernel text!?\n",
-+ __func__);
-+
-+ return 0;
-+}
-+
-+/*
-+ * File ops
-+ */
-+static long imr_test_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ int ret = -EINVAL;
-+
-+ switch (cmd) {
-+ case IOCTL_CLN_SANITY_CHECK_PUNIT_DMA:
-+ /* Check PUnit DMA actually works */
-+ ret = punit_dma_sanity_check();
-+ break;
-+ case IOCTL_CLN_IMR_1:
-+ /* Kernel IMR violation: PUnit DMA access */
-+ ret = imr_violate_kernel_punit_dma();
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+static int imr_test_open(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&imr_test_mutex);
-+ nonseekable_open(inode, file);
-+
-+ if (mutex_lock_interruptible(&imr_test_dev.open_lock)) {
-+ mutex_unlock(&imr_test_mutex);
-+ return -ERESTARTSYS;
-+ }
-+
-+ if (imr_test_dev.opened) {
-+ mutex_unlock(&imr_test_dev.open_lock);
-+ mutex_unlock(&imr_test_mutex);
-+ return -EINVAL;
-+ }
-+
-+ imr_test_dev.opened++;
-+ mutex_unlock(&imr_test_dev.open_lock);
-+ mutex_unlock(&imr_test_mutex);
-+ return 0;
-+}
-+
-+static int imr_test_release(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&imr_test_dev.open_lock);
-+ imr_test_dev.opened = 0;
-+ mutex_unlock(&imr_test_dev.open_lock);
-+
-+ return 0;
-+}
-+
-+static const struct file_operations imr_test_file_ops = {
-+ .open = imr_test_open,
-+ .release = imr_test_release,
-+ .unlocked_ioctl = imr_test_ioctl,
-+ .llseek = no_llseek,
-+};
-+
-+/**
-+ * intel_cln_imr_test_probe
-+ *
-+ * @param pdev: Platform device
-+ * @return 0 success < 0 failure
-+ *
-+ * Callback from platform sub-system to probe
-+ */
-+static int intel_cln_imr_test_probe(struct platform_device * pdev)
-+{
-+ int retval = 0;
-+ unsigned int minor = 0;
-+
-+ mutex_init(&imr_test_dev.open_lock);
-+ cdev_init(&imr_test_dev.cdev, &imr_test_file_ops);
-+ imr_test_dev.cdev.owner = THIS_MODULE;
-+
-+ retval = cdev_add(&imr_test_dev.cdev, MKDEV(imr_test_major, minor), 1);
-+ if (retval) {
-+ printk(KERN_ERR "chardev registration failed\n");
-+ return -EINVAL;
-+ }
-+ if (IS_ERR(device_create(imr_test_class, NULL,
-+ MKDEV(imr_test_major, minor), NULL,
-+ "imrtest%u", minor))){
-+ dev_err(&pdev->dev, "can't create device\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+
-+}
-+
-+static int intel_cln_imr_test_remove(struct platform_device * pdev)
-+{
-+ unsigned int minor = MINOR(imr_test_dev.cdev.dev);
-+
-+ device_destroy(imr_test_class, MKDEV(imr_test_major, minor));
-+ cdev_del(&imr_test_dev.cdev);
-+
-+ class_destroy(imr_test_class);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Platform structures useful for interface to PM subsystem
-+ */
-+static struct platform_driver intel_cln_imr_test_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .remove = intel_cln_imr_test_remove,
-+};
-+
-+/**
-+ * intel_cln_imr_test_init
-+ *
-+ * Load module.
-+ */
-+static int __init intel_cln_imr_test_init(void)
-+{
-+ int retval = 0;
-+ dev_t dev;
-+
-+ imr_test_class = class_create(THIS_MODULE,"cln_imr_test");
-+ if (IS_ERR(imr_test_class)) {
-+ retval = PTR_ERR(imr_test_class);
-+ printk(KERN_ERR "imr_test: can't register imr_test class\n");
-+ goto err;
-+ }
-+
-+ retval = alloc_chrdev_region(&dev, 0, 1, "imr_test");
-+ if (retval) {
-+ printk(KERN_ERR "earam_test: can't register character device\n");
-+ goto err_class;
-+ }
-+ imr_test_major = MAJOR(dev);
-+
-+ memset(&imr_test_dev, 0x00, sizeof(imr_test_dev));
-+ imr_test_dev.pldev = platform_create_bundle(
-+ &intel_cln_imr_test_driver, intel_cln_imr_test_probe, NULL, 0, NULL, 0);
-+
-+ if(IS_ERR(imr_test_dev.pldev)){
-+ printk(KERN_ERR "platform_create_bundle fail!\n");
-+ retval = PTR_ERR(imr_test_dev.pldev);
-+ goto err_class;
-+ }
-+
-+ return 0;
-+
-+err_class:
-+ class_destroy(imr_test_class);
-+err:
-+ return retval;
-+}
-+
-+static void __exit intel_cln_imr_test_exit(void)
-+{
-+ platform_device_unregister(imr_test_dev.pldev);
-+ platform_driver_unregister(&intel_cln_imr_test_driver);
-+}
-+
-+module_init(intel_cln_imr_test_init);
-+module_exit(intel_cln_imr_test_exit);
-+
-+MODULE_AUTHOR("Josef Ahmad <josef.ahmad@intel.com>");
-+MODULE_DESCRIPTION("Clanton IMR test module");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_plat_clanton_hill.c b/drivers/platform/x86/quark/intel_cln_plat_clanton_hill.c
-new file mode 100644
-index 0000000..7dac528
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_plat_clanton_hill.c
-@@ -0,0 +1,196 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton Legacy Platform Data Layout.conf accessor
-+ *
-+ * Simple Legacy SPI flash access layer
-+ *
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/i2c.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/spi/pxa2xx_spi.h>
-+#include <linux/spi/spi.h>
-+
-+#define DRIVER_NAME "ClantonHill"
-+#define GPIO_RESTRICT_NAME "cln-gpio-restrict-nc"
-+
-+/******************************************************************************
-+ * Analog Devices AD7298 SPI Device Platform Data
-+ ******************************************************************************/
-+#include "linux/platform_data/ad7298.h"
-+
-+/* Maximum input voltage allowed for each ADC input, in milliVolts */
-+#define AD7298_MAX_EXT_VIN 5000
-+#define AD7298_MAX_EXT_VIN_EXT_BATT 30000
-+#define AD7298_MAX_EXT_VIN_INT_BATT 9200
-+
-+static const struct ad7298_platform_data ad7298_platform_data = {
-+ .ext_ref = false,
-+ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN_EXT_BATT, AD7298_MAX_EXT_VIN_INT_BATT }
-+};
-+
-+/******************************************************************************
-+ * Intel Clanton SPI Controller Data
-+ ******************************************************************************/
-+static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
-+ .gpio_cs = 8,
-+};
-+
-+static struct spi_board_info spi_onboard_devs[] = {
-+ {
-+ .modalias = "ad7298",
-+ .max_speed_hz = 5000000,
-+ .platform_data = &ad7298_platform_data,
-+ .mode = SPI_MODE_2,
-+ .bus_num = 0,
-+ .chip_select = 0,
-+ .controller_data = &cln_ffrd_spi_0_cs_0,
-+ },
-+};
-+
-+/******************************************************************************
-+ * ST Microelectronics LIS331DLH I2C Device Platform Data
-+ ******************************************************************************/
-+#include <linux/platform_data/lis331dlh_intel_cln.h>
-+
-+/* GPIO interrupt pins connected to the LIS331DLH */
-+#define ST_ACCEL_INT1_GPIO 15
-+#define ST_ACCEL_INT2_GPIO 4
-+
-+static struct lis331dlh_intel_cln_platform_data lis331dlh_i2c_platform_data = {
-+ .irq1_pin = ST_ACCEL_INT1_GPIO,
-+};
-+
-+static struct gpio reserved_gpios[] = {
-+ {
-+ ST_ACCEL_INT1_GPIO,
-+ GPIOF_IN,
-+ "st_accel_i2c-int1"
-+ },
-+ {
-+ ST_ACCEL_INT2_GPIO,
-+ GPIOF_IN,
-+ "st_accel_i2c-int2"
-+ },
-+};
-+
-+static struct i2c_board_info i2c_onboard_devs[] = {
-+ {
-+ I2C_BOARD_INFO("intel-cln-max9867", 0x18),
-+ },
-+ {
-+ I2C_BOARD_INFO("lis331dlh_cln", 0x19),
-+ .platform_data = &lis331dlh_i2c_platform_data,
-+ },
-+};
-+
-+/**
-+ * intel_cln_spi_add_onboard_devs
-+ *
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Registers onboard SPI device(s) present on the Clanton Hill platform
-+ */
-+static int intel_cln_spi_add_onboard_devs(void)
-+{
-+ return spi_register_board_info(spi_onboard_devs,
-+ ARRAY_SIZE(spi_onboard_devs));
-+}
-+
-+/**
-+ * intel_cln_i2c_add_onboard_devs
-+ *
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Registers onboard I2C device(s) present on the Clanton Hill platform
-+ */
-+static int intel_cln_i2c_add_onboard_devs(void)
-+{
-+ return i2c_register_board_info(0, i2c_onboard_devs,
-+ ARRAY_SIZE(i2c_onboard_devs));
-+}
-+
-+
-+/**
-+ * intel_cln_gpio_restrict_probe
-+ *
-+ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
-+ * GPIOs are never released nor accessed by this driver.
-+ */
-+static int intel_cln_gpio_restrict_probe(struct platform_device *pdev)
-+{
-+ int ret = gpio_request_array(reserved_gpios,
-+ ARRAY_SIZE(reserved_gpios));
-+ if (ret == 0)
-+ ret = intel_cln_spi_add_onboard_devs();
-+
-+ return ret;
-+}
-+
-+static struct platform_driver gpio_restrict_pdriver = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe,
-+};
-+
-+static int intel_cln_plat_clanton_hill_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ ret = intel_cln_i2c_add_onboard_devs();
-+ if (ret == 0)
-+ ret = platform_driver_register(&gpio_restrict_pdriver);
-+
-+ return ret;
-+}
-+
-+static int intel_cln_plat_clanton_hill_remove(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+static struct platform_driver cln_clanton_hill_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_plat_clanton_hill_probe,
-+ .remove = intel_cln_plat_clanton_hill_remove,
-+};
-+
-+module_platform_driver(cln_clanton_hill_driver);
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("Clanton Hill BSP Data");
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_plat_clanton_peak.c b/drivers/platform/x86/quark/intel_cln_plat_clanton_peak.c
-new file mode 100644
-index 0000000..0341606
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_plat_clanton_peak.c
-@@ -0,0 +1,227 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Clanton Peak board entry point
-+ *
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/spi/spi.h>
-+#include <linux/spi/spi_bitbang.h>
-+#include <linux/spi/spi_gpio.h>
-+
-+#define DRIVER_NAME "ClantonPeakSVP"
-+#define GPIO_RESTRICT_NAME_NC "cln-gpio-restrict-nc"
-+#define GPIO_RESTRICT_NAME_SC "cln-gpio-restrict-sc"
-+
-+
-+/* GPIO connected to Test Equipment */
-+#define SUT_GPIO_NC_3 0x03
-+#define SUT_GPIO_NC_4 0x04
-+#define SUT_GPIO_NC_5 0x05
-+#define SUT_GPIO_NC_6 0x06
-+#define SUT_GPIO_SC_2 0x0A
-+#define SUT_GPIO_SC_3 0x0B
-+#define SUT_GPIO_SC_4 0x0C
-+#define SUT_GPIO_SC_5 0x0D
-+
-+#define GPIO_NC_BITBANG_SPI_BUS 2
-+#define GPIO_SC_BITBANG_SPI_BUS 3
-+
-+static struct spi_board_info spi_onboard_devs[] = {
-+ {
-+ .modalias = "spidev",
-+ .chip_select = 0,
-+ .max_speed_hz = 50000000,
-+ .bus_num = 0,
-+ },
-+ {
-+ .modalias = "spidev",
-+ .chip_select = 0,
-+ .max_speed_hz = 50000000,
-+ .bus_num = 1,
-+ },
-+};
-+
-+/*
-+ * Define platform data for bitbanged SPI devices.
-+ * Assign GPIO to SCK/MOSI/MISO
-+ */
-+static struct spi_gpio_platform_data spi_gpio_nc_data = {
-+ .sck = SUT_GPIO_NC_3,
-+ .mosi = SUT_GPIO_NC_4,
-+ .miso = SUT_GPIO_NC_5,
-+ .num_chipselect = 1,
-+};
-+static struct spi_gpio_platform_data spi_gpio_sc_data = {
-+ .sck = SUT_GPIO_SC_2,
-+ .mosi = SUT_GPIO_SC_3,
-+ .miso = SUT_GPIO_SC_4,
-+ .num_chipselect = 1,
-+};
-+
-+/*
-+ * Board information for bitbanged SPI devices.
-+ */
-+static const struct spi_board_info spi_gpio_nc_bi[] = {
-+ {
-+ .modalias = "spidev",
-+ .max_speed_hz = 1000,
-+ .bus_num = GPIO_NC_BITBANG_SPI_BUS,
-+ .mode = SPI_MODE_0,
-+ .platform_data = &spi_gpio_nc_data,
-+ /* Assign GPIO to CS */
-+ .controller_data = (void *)SUT_GPIO_NC_6,
-+ },
-+};
-+static const struct spi_board_info spi_gpio_sc_bi[] = {
-+ {
-+ .modalias = "spidev",
-+ .max_speed_hz = 1000,
-+ .bus_num = GPIO_SC_BITBANG_SPI_BUS,
-+ .mode = SPI_MODE_0,
-+ .platform_data = &spi_gpio_sc_data,
-+ /* Assign GPIO to CS */
-+ .controller_data = (void *)SUT_GPIO_SC_5,
-+ },
-+};
-+
-+static struct platform_device spi_gpio_nc_pd = {
-+ .name = "spi_gpio",
-+ .id = GPIO_NC_BITBANG_SPI_BUS,
-+ .dev = {
-+ .platform_data = &spi_gpio_nc_data,
-+ },
-+};
-+
-+static struct platform_device spi_gpio_sc_pd = {
-+ .name = "spi_gpio",
-+ .id = GPIO_SC_BITBANG_SPI_BUS,
-+ .dev = {
-+ .platform_data = &spi_gpio_sc_data,
-+ },
-+};
-+
-+/**
-+ * intel_cln_spi_add_onboard_devs
-+ *
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Registers onboard SPI device(s) present on the Clanton Peak platform
-+ */
-+static int intel_cln_spi_add_onboard_devs(void)
-+{
-+ return spi_register_board_info(spi_onboard_devs,
-+ ARRAY_SIZE(spi_onboard_devs));
-+}
-+
-+static int register_bitbanged_spi(int nc)
-+{
-+ int ret = 0;
-+
-+ ret = platform_device_register(nc ? &spi_gpio_nc_pd : &spi_gpio_sc_pd);
-+ if (ret)
-+ goto err;
-+
-+ ret = spi_register_board_info(nc ? spi_gpio_nc_bi : spi_gpio_sc_bi,
-+ nc ? ARRAY_SIZE(spi_gpio_nc_bi) :
-+ ARRAY_SIZE(spi_gpio_sc_bi));
-+ if (ret)
-+ goto err_unregister;
-+
-+ return 0;
-+
-+err_unregister:
-+ platform_device_unregister(nc ? &spi_gpio_nc_pd : &spi_gpio_sc_pd);
-+err:
-+ return ret;
-+}
-+
-+static int intel_cln_gpio_restrict_probe_nc(struct platform_device *pdev)
-+{
-+ return register_bitbanged_spi(1);
-+}
-+
-+static int intel_cln_gpio_restrict_probe_sc(struct platform_device *pdev)
-+{
-+ return register_bitbanged_spi(0);
-+}
-+
-+static struct platform_driver gpio_restrict_pdriver_nc = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME_NC,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe_nc,
-+};
-+
-+static struct platform_driver gpio_restrict_pdriver_sc = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME_SC,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe_sc,
-+};
-+
-+static int intel_cln_plat_clanton_peak_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ ret = platform_driver_register(&gpio_restrict_pdriver_nc);
-+ if (ret) {
-+ pr_err("%s: couldn't register %s platform driver\n",
-+ __func__, gpio_restrict_pdriver_nc.driver.name);
-+ }
-+
-+ ret = platform_driver_register(&gpio_restrict_pdriver_sc);
-+ if (ret) {
-+ pr_err("%s: couldn't register %s platform driver\n",
-+ __func__, gpio_restrict_pdriver_sc.driver.name);
-+ }
-+
-+ return intel_cln_spi_add_onboard_devs();
-+}
-+
-+static int intel_cln_plat_clanton_peak_remove(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+static struct platform_driver clanton_peak_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_plat_clanton_peak_probe,
-+ .remove = intel_cln_plat_clanton_peak_remove,
-+};
-+
-+module_platform_driver(clanton_peak_driver);
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("Clanton Peak BSP Data");
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-diff --git a/drivers/platform/x86/quark/intel_cln_plat_cross_hill.c b/drivers/platform/x86/quark/intel_cln_plat_cross_hill.c
-new file mode 100644
-index 0000000..263c07b
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_plat_cross_hill.c
-@@ -0,0 +1,383 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * CrossHill board entry point
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/spi/pxa2xx_spi.h>
-+#include <linux/spi/spi.h>
-+
-+#define DRIVER_NAME "CrossHill"
-+#define GPIO_RESTRICT_NAME_NC "cln-gpio-restrict-nc"
-+#define GPIO_RESTRICT_NAME_SC "cln-gpio-restrict-sc"
-+
-+/*
-+ * GPIO numbers to use for reading 4-bit Blackburn Peak SPI daughterboard ID
-+ */
-+#define SPI_BPEAK_RESET_GPIO 4
-+#define SPI_BPEAK_ID0_GPIO 3
-+#define SPI_BPEAK_ID1_GPIO 2
-+#define SPI_BPEAK_ID2_GPIO 15
-+#define SPI_BPEAK_ID3_GPIO 14
-+
-+static int nc_gpio_reg;
-+static int sc_gpio_reg;
-+
-+static int cross_hill_probe;
-+
-+/*
-+ * Blackburn Peak SPI daughterboard ID values
-+ */
-+enum {
-+ CLN_SPI_BPEAK_ID_ZB_TI = 0xA,
-+ CLN_SPI_BPEAK_ID_ZB_DIGI,
-+ CLN_SPI_BPEAK_ID_ZB_INFR_NXP,
-+ CLN_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL,
-+ CLN_SPI_BPEAK_ID_ADC_MAXIM,
-+ CLN_SPI_BPEAK_ID_NONE
-+};
-+
-+
-+/******************************************************************************
-+ * Analog Devices AD7298 SPI Device Platform Data
-+ ******************************************************************************/
-+#include "linux/platform_data/ad7298.h"
-+
-+/* Maximum input voltage allowed for each ADC input, in milliVolts */
-+#define AD7298_MAX_EXT_VIN 5000
-+
-+static const struct ad7298_platform_data ad7298_platform_data = {
-+ .ext_ref = false,
-+ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
-+};
-+
-+/******************************************************************************
-+ * Intel Clanton SPI Controller Data
-+ ******************************************************************************/
-+static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
-+ .gpio_cs = 8,
-+};
-+
-+static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_0 = {
-+ .gpio_cs = 10,
-+};
-+
-+static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_1 = {
-+ .gpio_cs = 11,
-+};
-+
-+static struct spi_board_info spi_generic_devs[] = {
-+ {
-+ .modalias = "spidev",
-+ .max_speed_hz = 50000000,
-+ .platform_data = NULL,
-+ .mode = SPI_MODE_0,
-+ .bus_num = 1,
-+ .chip_select = 0,
-+ .controller_data = &cln_ffrd_spi_1_cs_0,
-+ },
-+
-+ {
-+ .modalias = "spidev",
-+ .max_speed_hz = 50000000,
-+ .platform_data = NULL,
-+ .mode = SPI_MODE_0,
-+ .bus_num = 1,
-+ .chip_select = 1,
-+ .controller_data = &cln_ffrd_spi_1_cs_1,
-+ },
-+
-+};
-+
-+static struct spi_board_info spi_energy_adc_devs[] = {
-+ {
-+ .modalias = "max78m6610_lmu",
-+ .max_speed_hz = 2000000,
-+ .platform_data = NULL,
-+ .mode = SPI_MODE_3,
-+ .bus_num = 1,
-+ .chip_select = 0,
-+ .controller_data = &cln_ffrd_spi_1_cs_0,
-+ },
-+};
-+
-+
-+
-+/**
-+ * intel_cln_spi_add_onboard_devs
-+ *
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Registers onboard SPI device(s) present on the Cross Hill platform
-+ */
-+static int intel_cln_spi_add_onboard_devs(void)
-+{
-+ struct spi_board_info spi_onboard_devs[] = {
-+ {
-+ .modalias = "ad7298",
-+ .max_speed_hz = 5000000,
-+ .platform_data = &ad7298_platform_data,
-+ .mode = SPI_MODE_2,
-+ .bus_num = 0,
-+ .chip_select = 0,
-+ .controller_data = &cln_ffrd_spi_0_cs_0,
-+ },
-+ };
-+
-+ return spi_register_board_info(spi_onboard_devs,
-+ ARRAY_SIZE(spi_onboard_devs));
-+}
-+
-+
-+/**
-+ * intel_cln_spi_get_bpeak_id
-+ *
-+ * @param bpeak_id: The Blackburn Peak SPI ID obtained from the daughterboard
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Reads an ID from GPIO-connected pins on Blackburn peak SPI daughterboard
-+ */
-+static int intel_cln_spi_get_bpeak_id(u8 *bpeak_id)
-+{
-+ int ret = 0;
-+ struct gpio spi_bpeak_id_gpios[] = {
-+ {
-+ SPI_BPEAK_RESET_GPIO,
-+ GPIOF_OUT_INIT_HIGH,
-+ "spi_bpeak_reset"
-+ },
-+ {
-+ SPI_BPEAK_ID0_GPIO,
-+ GPIOF_IN,
-+ "spi_bpeak_id0"
-+ },
-+ {
-+ SPI_BPEAK_ID1_GPIO,
-+ GPIOF_IN,
-+ "spi_bpeak_id1"
-+ },
-+ {
-+ SPI_BPEAK_ID2_GPIO,
-+ GPIOF_IN,
-+ "spi_bpeak_id2"
-+ },
-+ {
-+ SPI_BPEAK_ID3_GPIO,
-+ GPIOF_IN,
-+ "spi_bpeak_id3"
-+ }
-+ };
-+
-+ /*
-+ * Read a 4-bit ID value from ID GPIO inputs, which are only valid
-+ * while a RESET GPIO output is asserted (active-low)
-+ */
-+ ret = gpio_request_array(spi_bpeak_id_gpios,
-+ ARRAY_SIZE(spi_bpeak_id_gpios));
-+ if (ret) {
-+ pr_err("%s: Failed to allocate Blackburn Peak ID GPIO pins\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ gpio_set_value(SPI_BPEAK_RESET_GPIO, 0);
-+ *bpeak_id =
-+ (gpio_get_value(SPI_BPEAK_ID3_GPIO) ? 1 << 3 : 0) |
-+ (gpio_get_value(SPI_BPEAK_ID2_GPIO) ? 1 << 2 : 0) |
-+ (gpio_get_value(SPI_BPEAK_ID1_GPIO) ? 1 << 1 : 0) |
-+ (gpio_get_value(SPI_BPEAK_ID0_GPIO) ? 1 : 0);
-+ gpio_set_value(SPI_BPEAK_RESET_GPIO, 1);
-+
-+ gpio_free_array(spi_bpeak_id_gpios,
-+ ARRAY_SIZE(spi_bpeak_id_gpios));
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_spi_add_bpeak_devs
-+ *
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Registers SPI device(s) indicated by the ID value obtained from a
-+ * Blackburn Peak SPI daughterboard
-+ */
-+static int intel_cln_spi_add_bpeak_devs(void)
-+{
-+ u8 spi_bpeak_id = 0;
-+ int ret = 0;
-+
-+ ret = intel_cln_spi_get_bpeak_id(&spi_bpeak_id);
-+ if (ret) {
-+ pr_err("%s: failed to obtain Blackburn Peak ID\n",
-+ __func__);
-+ return ret;
-+ }
-+
-+ switch (spi_bpeak_id) {
-+
-+ case CLN_SPI_BPEAK_ID_NONE:
-+ break;
-+
-+ case CLN_SPI_BPEAK_ID_ADC_MAXIM:
-+ {
-+ return spi_register_board_info(spi_energy_adc_devs,
-+ ARRAY_SIZE(spi_energy_adc_devs));
-+ }
-+ case CLN_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL:
-+ {
-+ pr_debug("CLN_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL.\n");
-+ return spi_register_board_info(spi_generic_devs,
-+ ARRAY_SIZE(spi_generic_devs));
-+ }
-+ case CLN_SPI_BPEAK_ID_ZB_DIGI:
-+ {
-+ pr_debug("CLN_SPI_BPEAK_ID_ZB_DIGI load.\n");
-+ return spi_register_board_info(spi_generic_devs,
-+ ARRAY_SIZE(spi_generic_devs));
-+
-+ }
-+ default:
-+ pr_err("%s: Unsupported Blackburn Peak SPI ID %u\n",
-+ __func__, spi_bpeak_id);
-+ ret = -EINVAL;
-+ }
-+
-+ return ret;
-+}
-+
-+/** intel_cln_spi_devs_addon
-+ *
-+ * addon spi device when gpio support in place
-+ */
-+static int intel_cln_spi_devs_addon(void)
-+{
-+ int ret = 0;
-+
-+ if (cross_hill_probe != 1) {
-+
-+ ret = intel_cln_spi_add_onboard_devs();
-+ if (ret)
-+ return ret;
-+
-+ ret = intel_cln_spi_add_bpeak_devs();
-+
-+ cross_hill_probe = 1;
-+ }
-+
-+ return ret;
-+}
-+
-+/**
-+ * intel_cln_gpio_restrict_probe_nc
-+ *
-+ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
-+ * GPIOs are never released nor accessed by this driver.
-+ */
-+static int intel_cln_gpio_restrict_probe_nc(struct platform_device *pdev)
-+{
-+ int ret;
-+ nc_gpio_reg = 1;
-+
-+ if (nc_gpio_reg == 1 && sc_gpio_reg == 1) {
-+ ret = intel_cln_spi_devs_addon();
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_gpio_restrict_probe_sc
-+ *
-+ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
-+ * GPIOs are never released nor accessed by this driver.
-+ */
-+static int intel_cln_gpio_restrict_probe_sc(struct platform_device *pdev)
-+{
-+ int ret;
-+ sc_gpio_reg = 1;
-+
-+ if (nc_gpio_reg == 1 && sc_gpio_reg == 1) {
-+ ret = intel_cln_spi_devs_addon();
-+ if (ret)
-+ return ret;
-+ }
-+ return 0;
-+}
-+
-+static struct platform_driver gpio_restrict_pdriver_nc = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME_NC,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe_nc,
-+};
-+
-+static struct platform_driver gpio_restrict_pdriver_sc = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME_SC,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe_sc,
-+};
-+
-+static int intel_cln_plat_cross_hill_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ ret = platform_driver_register(&gpio_restrict_pdriver_nc);
-+ if (ret)
-+ return ret;
-+
-+ return platform_driver_register(&gpio_restrict_pdriver_sc);
-+}
-+
-+static int intel_cln_plat_cross_hill_remove(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+static struct platform_driver cln_cross_hill_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_plat_cross_hill_probe,
-+ .remove = intel_cln_plat_cross_hill_remove,
-+};
-+
-+module_platform_driver(cln_cross_hill_driver);
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("Cross Hill BSP Data");
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_plat_galileo.c b/drivers/platform/x86/quark/intel_cln_plat_galileo.c
-new file mode 100644
-index 0000000..364358c
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_plat_galileo.c
-@@ -0,0 +1,395 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton Legacy Platform Data Layout.conf accessor
-+ *
-+ * Simple Legacy SPI flash access layer
-+ *
-+ * 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/cy8c9540a.h>
-+#include <linux/mfd/intel_cln_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/at24.h>
-+
-+#define DRIVER_NAME "Galileo"
-+#define GPIO_RESTRICT_NAME "cln-gpio-restrict-sc"
-+#define LPC_SCH_SPINAME "spi-lpc-sch"
-+
-+#define CLN_SPI_MAX_CLK_DEFAULT 5000000
-+
-+/* GPIO line used to detect the LSB of the Cypress i2c address */
-+#define GPIO_CYPRESS_A0 7
-+/* GPIO line Cypress interrupts are routed to (in S0 power state) */
-+#define GPIO_CYPRESS_INT_S0 13
-+/* GPIO line Cypress interrupts are routed to (in S3 power state) */
-+#define GPIO_CYPRESS_INT_S3 2
-+
-+/* Cypress i2c address depending on A0 value */
-+#define CYPRESS_ADDR_A0_1 0x20
-+#define CYPRESS_ADDR_A0_0 0x21
-+
-+/******************************************************************************
-+ * Cypress I/O Expander Platform Data
-+ ******************************************************************************/
-+static struct cy8c9540a_pdata cy8c9540a_platform_data = {
-+ .por_default = {
-+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Output */
-+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Int mask */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* PWM */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Inversion */
-+ 0xe0, 0xe0, 0xff, 0xf3, 0x00, 0xff, 0xff, 0xff, /* Direction */
-+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* P0 drive */
-+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* P1 drive */
-+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P2 drive */
-+ 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, /* P3 drive */
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* P4 drive */
-+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P5 drive */
-+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P6 drive */
-+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* P7 drive */
-+ 0x00, 0xff, 0x00, /* PWM0 */
-+ 0x00, 0xff, 0x00, /* PWM1 */
-+ 0x00, 0xff, 0x00, /* PWM2 */
-+ 0x00, 0xff, 0x00, /* PWM3 */
-+ 0x00, 0xff, 0x00, /* PWM4 */
-+ 0x00, 0xff, 0x00, /* PWM5 */
-+ 0x00, 0xff, 0x00, /* PWM6 */
-+ 0x00, 0xff, 0x00, /* PWM7 */
-+ 0x00, 0xff, 0x00, /* PWM8 */
-+ 0x00, 0xff, 0x00, /* PWM9 */
-+ 0x00, 0xff, 0x00, /* PWM10 */
-+ 0x00, 0xff, 0x00, /* PWM11 */
-+ 0x00, 0xff, 0x00, /* PWM12 */
-+ 0x00, 0xff, 0x00, /* PWM13 */
-+ 0x00, 0xff, 0x00, /* PWM14 */
-+ 0x00, 0xff, 0x00, /* PWM15 */
-+ 0xff, /* PWM CLKdiv */
-+ 0x02, /* EEPROM en */
-+ 0x00 /* CRC */
-+ },
-+ .pwm2gpio_mapping = {
-+ CY8C9540A_PWM_UNUSED,
-+ 3,
-+ CY8C9540A_PWM_UNUSED,
-+ 2,
-+ 9,
-+ 1,
-+ 8,
-+ 0,
-+ },
-+ .gpio_base = 16,
-+ .pwm_base = 0,
-+ .irq_base = 64,
-+};
-+
-+/* Cypress expander requires i2c master to operate @100kHz 'standard mode' */
-+static struct intel_cln_gip_pdata gip_pdata = {
-+ .i2c_std_mode = 1,
-+};
-+static struct intel_cln_gip_pdata *galileo_gip_get_pdata(void)
-+{
-+ return &gip_pdata;
-+}
-+
-+/******************************************************************************
-+ * Analog Devices AD7298 SPI Device Platform Data
-+ ******************************************************************************/
-+#include "linux/platform_data/ad7298.h"
-+
-+/* Maximum input voltage allowed for each ADC input, in milliVolts */
-+#define AD7298_MAX_EXT_VIN 5000
-+
-+static const struct ad7298_platform_data ad7298_platform_data = {
-+ .ext_ref = false,
-+ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
-+};
-+
-+static struct at24_platform_data at24_platform_data = {
-+ .byte_len = (11 * 1024),
-+ .page_size = 1,
-+ .flags = AT24_FLAG_ADDR16,
-+};
-+
-+/******************************************************************************
-+ * Intel Izmir i2c clients
-+ ******************************************************************************/
-+static struct i2c_board_info __initdata static_i2c_board_info[] = {
-+ {
-+ I2C_BOARD_INFO("at24", 0x50),
-+ .platform_data = &at24_platform_data,
-+ },
-+};
-+static struct i2c_board_info probed_i2c_cypress = {
-+ .platform_data = &cy8c9540a_platform_data,
-+};
-+static struct i2c_adapter *i2c_adap;
-+static const unsigned short cypress_i2c_addr[] =
-+ { CYPRESS_ADDR_A0_1, CYPRESS_ADDR_A0_0, I2C_CLIENT_END };
-+
-+/******************************************************************************
-+ * Intel Clanton SPI Controller Data
-+ ******************************************************************************/
-+static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
-+ .gpio_cs = 8,
-+};
-+
-+static struct pxa2xx_spi_chip cln_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 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 = ilb_partitions,
-+ .nr_parts = ARRAY_SIZE(ilb_partitions),
-+};
-+
-+static struct spi_board_info spi_onboard_devs[] = {
-+ {
-+ .modalias = "m25p80",
-+ .platform_data = &ilb_flash,
-+ .bus_num = LPC_SCH_SPI_BUS_ID,
-+ .chip_select = 0,
-+ },
-+ {
-+ .modalias = "ad7298",
-+ .max_speed_hz = CLN_SPI_MAX_CLK_DEFAULT,
-+ .platform_data = &ad7298_platform_data,
-+ .mode = SPI_MODE_2,
-+ .bus_num = 0,
-+ .chip_select = 0,
-+ .controller_data = &cln_ffrd_spi_0_cs_0,
-+ },
-+ {
-+ .modalias = "spidev",
-+ .chip_select = 0,
-+ .controller_data = &cln_ffrd_spi_1_cs_0,
-+ .max_speed_hz = 50000000,
-+ .bus_num = 1,
-+ },
-+};
-+
-+static struct gpio reserved_gpios[] = {
-+ {
-+ GPIO_CYPRESS_A0,
-+ GPIOF_IN,
-+ "cy8c9540a-a0",
-+ },
-+ {
-+ GPIO_CYPRESS_INT_S0,
-+ GPIOF_IN,
-+ "cy8c9540a-int-s0",
-+ },
-+ {
-+ GPIO_CYPRESS_INT_S3,
-+ GPIOF_IN,
-+ "cy8c9540a-int-s3",
-+ },
-+};
-+
-+static int cypress_i2c_probe(struct i2c_adapter *adap, unsigned short addr)
-+{
-+ if (gpio_get_value(GPIO_CYPRESS_A0) && CYPRESS_ADDR_A0_1 == addr)
-+ return 1;
-+ if (!gpio_get_value(GPIO_CYPRESS_A0) && CYPRESS_ADDR_A0_0 == addr)
-+ return 1;
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_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_cln_spi_add_onboard_devs(void)
-+{
-+
-+ return spi_register_board_info(spi_onboard_devs,
-+ ARRAY_SIZE(spi_onboard_devs));
-+}
-+
-+
-+/**
-+ * intel_cln_gpio_restrict_probe
-+ *
-+ * Register devices that depend on GPIOs.
-+ * Note this function makes extensive use of the probe deferral mechanism:
-+ * gpio_request() for a GPIO that is not yet available returns
-+ * -EPROBE_DEFER.
-+ */
-+static int intel_cln_gpio_restrict_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+ struct i2c_client *cypress = NULL;
-+ static int spi_done;
-+ static int gpios_done;
-+
-+ if (spi_done)
-+ goto gpios;
-+
-+ ret = intel_cln_spi_add_onboard_devs();
-+ if (ret)
-+ goto end;
-+
-+ spi_done = 1;
-+
-+gpios:
-+ if (gpios_done)
-+ goto i2c;
-+
-+ ret = gpio_request_array(reserved_gpios, ARRAY_SIZE(reserved_gpios));
-+ if (ret)
-+ goto end;
-+
-+ probed_i2c_cypress.irq = gpio_to_irq(GPIO_CYPRESS_INT_S0);
-+
-+ gpios_done = 1;
-+
-+i2c:
-+ i2c_adap = i2c_get_adapter(0);
-+ if (NULL == i2c_adap) {
-+ pr_info("%s: i2c adapter not ready yet. Deferring..\n",
-+ __func__);
-+ ret = -EPROBE_DEFER;
-+ goto end;
-+ }
-+ strlcpy(probed_i2c_cypress.type, "cy8c9540a", I2C_NAME_SIZE);
-+ cypress = i2c_new_probed_device(i2c_adap, &probed_i2c_cypress,
-+ cypress_i2c_addr, cypress_i2c_probe);
-+ i2c_put_adapter(i2c_adap);
-+
-+ if (NULL == cypress) {
-+ pr_err("%s: can't probe Cypress Expander\n", __func__);
-+ ret = -ENODEV;
-+ goto end;
-+ }
-+
-+end:
-+ return ret;
-+}
-+
-+static struct platform_driver gpio_restrict_pdriver = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe,
-+};
-+
-+static int intel_cln_plat_galileo_probe(struct platform_device *pdev)
-+{
-+ int ret = 0;
-+
-+ /* Assign GIP driver handle for board-specific settings */
-+ intel_cln_gip_get_pdata = galileo_gip_get_pdata;
-+
-+ /* i2c */
-+ ret = i2c_register_board_info(0, static_i2c_board_info,
-+ ARRAY_SIZE(static_i2c_board_info));
-+ if (ret) {
-+ goto end;
-+ }
-+
-+ /* gpio */
-+ ret = platform_driver_register(&gpio_restrict_pdriver);
-+ if (ret)
-+ goto end;
-+
-+#if 0
-+ /* legacy SPI - TBD */
-+ ret = platform_driver_register(&intel_cln_plat_galileo_lpcspi_pdriver);
-+ if (ret)
-+ goto end;
-+#endif
-+end:
-+ return ret;
-+}
-+
-+static int intel_cln_plat_galileo_remove(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+static struct platform_driver cln_galileo_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_plat_galileo_probe,
-+ .remove = intel_cln_plat_galileo_remove,
-+};
-+
-+module_platform_driver(cln_galileo_driver);
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("Galileo BSP Data");
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_plat_kips_bay.c b/drivers/platform/x86/quark/intel_cln_plat_kips_bay.c
-new file mode 100644
-index 0000000..f701e69
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_plat_kips_bay.c
-@@ -0,0 +1,176 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton Legacy Platform Data Layout.conf accessor
-+ *
-+ * Simple Legacy SPI flash access layer
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/gpio.h>
-+#include <linux/io.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/spi/pxa2xx_spi.h>
-+#include <linux/spi/spi.h>
-+
-+#define DRIVER_NAME "KipsBay"
-+#define GPIO_RESTRICT_NAME "cln-gpio-restrict-sc"
-+
-+static int gpio_cs = 1;
-+
-+module_param(gpio_cs, int, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(gpio_cs, "Enable GPIO chip-select for SPI channel 1");
-+
-+
-+/******************************************************************************
-+ * Analog Devices AD7298 SPI Device Platform Data
-+ ******************************************************************************/
-+#include "linux/platform_data/ad7298.h"
-+
-+/* Maximum input voltage allowed for each ADC input, in milliVolts */
-+#define AD7298_MAX_EXT_VIN 5000
-+
-+static const struct ad7298_platform_data ad7298_platform_data = {
-+ .ext_ref = false,
-+ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
-+ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
-+};
-+
-+/******************************************************************************
-+ * Intel Clanton SPI Controller Data
-+ ******************************************************************************/
-+static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
-+ .gpio_cs = 8,
-+};
-+
-+static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_0 = {
-+ .gpio_cs = 10,
-+};
-+
-+static struct spi_board_info spi0_onboard_devs[] = {
-+ {
-+ .modalias = "ad7298",
-+ .max_speed_hz = 5000000,
-+ .platform_data = &ad7298_platform_data,
-+ .mode = SPI_MODE_2,
-+ .bus_num = 0,
-+ .chip_select = 0,
-+ .controller_data = &cln_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 = &cln_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_cln_spi_add_onboard_devs
-+ *
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * Registers onboard SPI device(s) present on the Kips Bay platform
-+ */
-+static int intel_cln_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));
-+}
-+
-+
-+/**
-+ * intel_cln_gpio_restrict_probe
-+ *
-+ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
-+ * GPIOs are never released nor accessed by this driver.
-+ */
-+static int intel_cln_gpio_restrict_probe(struct platform_device *pdev)
-+{
-+ return intel_cln_spi_add_onboard_devs();
-+}
-+
-+static struct platform_driver gpio_restrict_pdriver = {
-+ .driver = {
-+ .name = GPIO_RESTRICT_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_gpio_restrict_probe,
-+};
-+
-+static int intel_cln_plat_kips_bay_probe(struct platform_device *pdev)
-+{
-+ return platform_driver_register(&gpio_restrict_pdriver);
-+}
-+
-+static int intel_cln_plat_kips_bay_remove(struct platform_device *pdev)
-+{
-+ return 0;
-+}
-+
-+static struct platform_driver cln_kips_bay_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_plat_kips_bay_probe,
-+ .remove = intel_cln_plat_kips_bay_remove,
-+};
-+
-+module_platform_driver(cln_kips_bay_driver);
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
-+MODULE_DESCRIPTION("Kips Bay BSP Data");
-+MODULE_LICENSE("Dual BSD/GPL");
-+MODULE_ALIAS("platform:"DRIVER_NAME);
-+
-diff --git a/drivers/platform/x86/quark/intel_cln_sb.c b/drivers/platform/x86/quark/intel_cln_sb.c
-new file mode 100644
-index 0000000..be27d6a
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_sb.c
-@@ -0,0 +1,252 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton side-band driver
-+ *
-+ * Thread-safe sideband read/write routine.
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2012
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/intel_cln_sb.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/spinlock.h>
-+#include <linux/pci.h>
-+#include "intel_cln_imr.h"
-+
-+#define INTEL_CLN_SB_CMD_ADDR (0x000000D0)
-+#define INTEL_CLN_SB_DATA_ADDR (0x000000D4)
-+
-+#define INTEL_CLN_SB_MCR_SHIFT (24)
-+#define INTEL_CLN_SB_PORT_SHIFT (16)
-+#define INTEL_CLN_SB_REG_SHIFT (8)
-+#define INTEL_CLN_SB_BYTEEN (0xF0) /* enable all 32 bits */
-+
-+/* Simple structure for module */
-+struct intel_cln_sb_dev{
-+ struct pci_dev * pdev;
-+ spinlock_t slock;
-+ u8 initialized;
-+};
-+
-+static struct intel_cln_sb_dev sb_dev = {
-+ .initialized = 0
-+};
-+
-+/* Dependant drivers */
-+static struct platform_device pdev [] = {
-+ {
-+ .name = "intel-cln-esram",
-+ },
-+ {
-+ .name = "intel-cln-ecc",
-+ },
-+ {
-+ .name = "intel-cln-thrm",
-+ },
-+};
-+
-+/**
-+ * intel_cln_sb_read_reg
-+ *
-+ * @param cln_sb_id: Sideband identifier
-+ * @param command: Command to send to destination identifier
-+ * @param reg: Target register w/r to cln_sb_id
-+ * @return nothing
-+ *
-+ * Utility function to allow thread-safe read of side-band
-+ * command - can be different read op-code types - which is why we don't
-+ * hard-code this value directly into msg
-+ */
-+void intel_cln_sb_read_reg(cln_sb_id id, u8 cmd, u8 reg, u32 *data, u8 lock)
-+{
-+ u32 msg = (cmd << INTEL_CLN_SB_MCR_SHIFT) |
-+ ((id << INTEL_CLN_SB_PORT_SHIFT) & 0xFF0000)|
-+ ((reg << INTEL_CLN_SB_REG_SHIFT) & 0xFF00)|
-+ INTEL_CLN_SB_BYTEEN;
-+
-+ if(data == NULL)
-+ return;
-+
-+ if (likely(lock == 1)) {
-+ spin_lock(&sb_dev.slock);
-+ }
-+
-+ pci_write_config_dword(sb_dev.pdev, INTEL_CLN_SB_CMD_ADDR, msg);
-+ pci_read_config_dword(sb_dev.pdev, INTEL_CLN_SB_DATA_ADDR, data);
-+
-+ if(likely(lock == 1)){
-+ spin_unlock(&sb_dev.slock);
-+ }
-+
-+}
-+EXPORT_SYMBOL(intel_cln_sb_read_reg);
-+
-+/**
-+ * intel_cln_sb_write_reg
-+ *
-+ * @param cln_sb_id: Sideband identifier
-+ * @param command: Command to send to destination identifier
-+ * @param reg: Target register w/r to cln_sb_id
-+ * @return nothing
-+ *
-+ * Utility function to allow thread-safe write of side-band
-+ */
-+void intel_cln_sb_write_reg(cln_sb_id id, u8 cmd, u8 reg, u32 data, u8 lock)
-+{
-+ u32 msg = (cmd << INTEL_CLN_SB_MCR_SHIFT) |
-+ ((id << INTEL_CLN_SB_PORT_SHIFT) & 0xFF0000)|
-+ ((reg << INTEL_CLN_SB_REG_SHIFT) & 0xFF00)|
-+ INTEL_CLN_SB_BYTEEN;
-+
-+ if(likely(lock == 1)){
-+ spin_lock(&sb_dev.slock);
-+ }
-+
-+ pci_write_config_dword(sb_dev.pdev, INTEL_CLN_SB_DATA_ADDR, data);
-+ pci_write_config_dword(sb_dev.pdev, INTEL_CLN_SB_CMD_ADDR, msg);
-+
-+ if(likely(lock == 1)){
-+ spin_unlock(&sb_dev.slock);
-+ }
-+}
-+EXPORT_SYMBOL(intel_cln_sb_write_reg);
-+
-+/**
-+ * intel_cln_sb_runfn_lock
-+ *
-+ * @param fn: Callback function - which requires side-band spinlock and !irq
-+ * @param arg: Callback argument
-+ * @return 0 on success < 0 on failure
-+ *
-+ * Runs the given function pointer inside of a call to the local spinlock using
-+ * spin_lock_irqsave/spin_unlock_irqrestore. Needed for the eSRAMv1 driver to
-+ * guarantee atomicity, but, available to any other user of sideband provided
-+ * rules are respected.
-+ * Rules:
-+ * fn may not sleep
-+ * fn may not change the state of irqs
-+ */
-+int intel_cln_sb_runfn_lock(int (*fn)( void * arg ), void * arg)
-+{
-+ unsigned long flags = 0;
-+ int ret = 0;
-+
-+ if(unlikely(fn == NULL)){
-+ return -EINVAL;
-+ }
-+
-+ /* Get spinlock with IRQs off */
-+ spin_lock_irqsave(&sb_dev.slock, flags);
-+
-+ /* Run function atomically */
-+ ret = fn(arg);
-+
-+ /* Release lock */
-+ spin_unlock_irqrestore(&sb_dev.slock, flags);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(intel_cln_sb_runfn_lock);
-+
-+/**
-+ * sb_probe
-+ *
-+ * @param dev: the PCI device matching
-+ * @param id: entry in the match table
-+ * @return 0
-+ *
-+ * Callback from PCI layer when dev/vendor ids match.
-+ * Sets up necessary resources
-+ */
-+static int intel_cln_sb_probe(struct pci_dev *dev, const struct pci_device_id *id)
-+{
-+ int i = 0;
-+
-+ /* Init struct */
-+ memset(&sb_dev, 0x00, sizeof(sb_dev));
-+
-+ /* Hook device */
-+ sb_dev.pdev = dev;
-+
-+ /* Init locking structures */
-+ spin_lock_init(&sb_dev.slock);
-+
-+ /* Set state */
-+ sb_dev.initialized = 1;
-+
-+ /* Register side-band sub-ordinate drivers */
-+ for (i = 0; i < sizeof(pdev)/sizeof(struct platform_device); i++){
-+ /* Register side-band sub-ordinate drivers */
-+ platform_device_register(&pdev[i]);
-+ }
-+ pr_info("Intel Clanton side-band driver registered\n");
-+
-+ /* Switch off boot-time IMRs nice and early */
-+ return intel_cln_imr_init();
-+}
-+
-+/**
-+ * sb_remove
-+ *
-+ * @param pdev: PCI device
-+ * @return nothing
-+ *
-+ * Callback from PCI sub-system upon PCI dev removal
-+ */
-+static void intel_cln_sb_remove(struct pci_dev *pdev)
-+{
-+}
-+
-+/* Clanton hardware */
-+struct pci_device_id intel_cln_sb_ids[] = {
-+ { PCI_VDEVICE(INTEL, 0x0958), 0},
-+ { 0 }
-+};
-+
-+MODULE_DEVICE_TABLE(pci, intel_cln_sb_ids);
-+
-+/* PCI callbacks */
-+static struct pci_driver intel_cln_sb_driver = {
-+ .name = "intel_cln_sb",
-+ .id_table = intel_cln_sb_ids,
-+ .probe = intel_cln_sb_probe,
-+ .remove = intel_cln_sb_remove,
-+};
-+
-+/**
-+ * intel_cln_sb_init
-+ *
-+ * Module entry point
-+ */
-+static int __init intel_cln_sb_init(void)
-+{
-+ return pci_register_driver(&intel_cln_sb_driver);
-+}
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
-+MODULE_DESCRIPTION("Intel Clanton SOC side-band driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+/* Initialise early since other drivers eSRAM, DRAM ECC and thermal depend */
-+subsys_initcall(intel_cln_sb_init);
-diff --git a/drivers/platform/x86/quark/intel_cln_smep_test.c b/drivers/platform/x86/quark/intel_cln_smep_test.c
-new file mode 100644
-index 0000000..16f43db
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_smep_test.c
-@@ -0,0 +1,290 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/**
-+ * intel_cln_smep_test.c
-+ *
-+ * Simple test module to verify SMEP works as expected on MIA
-+ * DO NOT RELEASE THIS FILE OUTSIDE OF CLANTON GROUP
-+ * DO NOT ATTEMPT TO UPSTREAM THIS CODE - YOU WILL BE PUBLICLY EMBARRSSED !
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@intel.com>
-+ *
-+ */
-+#include <asm/processor.h>
-+#include <asm/processor-flags.h>
-+#include <linux/cdev.h>
-+#include <linux/crc16.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/fs.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/printk.h>
-+#include <linux/slab.h>
-+
-+#define DRIVER_NAME "intel_cln_smep_test"
-+
-+/**
-+ * struct intel_cln_smep_dev
-+ *
-+ * Structre to represent module state/data/etc
-+ */
-+struct intel_cln_smep_test_dev{
-+ unsigned int opened;
-+ struct platform_device *pldev; /* Platform device */
-+ struct cdev cdev;
-+ struct mutex open_lock;
-+ char * pdata;
-+ u32 size;
-+};
-+
-+static struct intel_cln_smep_test_dev smep_test_dev;
-+static struct class *smep_test_class;
-+static DEFINE_MUTEX(smep_test_mutex);
-+static int smep_test_major;
-+static char * name = "testmap";
-+
-+/**
-+ * smep_test_ioctl
-+ *
-+ * Allows user-space to command kernel switch SMEP on/off
-+ */
-+static long smep_test_ioctl(struct file *file, unsigned int cmd,
-+ unsigned long arg)
-+{
-+ int cr4 = 0;
-+
-+ cr4 = read_cr4();
-+ printk(KERN_INFO "%s entry CR4 is 0x%08x\n", __FUNCTION__, cr4);
-+
-+ switch(cmd){
-+ case 0:
-+ printk(KERN_INFO "Switching SMEP off\n");
-+ cr4 &= ~X86_CR4_SMEP;
-+
-+ break;
-+ case 1:
-+ printk(KERN_INFO "Switching SMEP on\n");
-+ cr4 |= X86_CR4_SMEP;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ /* Latch value */
-+ write_cr4(cr4);
-+
-+ /* Print contents of CR4 */
-+ cr4 = read_cr4();
-+ printk(KERN_INFO "%s exit CR4 is 0x%08x\n", __FUNCTION__, cr4);
-+
-+ return 0;
-+}
-+
-+/**
-+ * smep_test_write
-+ *
-+ * Accepts a buffer from user-space and then tries to execute the contents
-+ * Be very careful
-+ */
-+static ssize_t smep_test_write(struct file *file, const char __user *buf,
-+ size_t count, loff_t *ppos)
-+{
-+ /*
-+ * We assume we are passed a pointer to function of type
-+ * void fn(void)
-+ */
-+ void (*fn)(void) = (void(*))buf;
-+ if (count) {
-+ printk(KERN_INFO "Will attempt exec %d bytes of ring3 code @ 0x%p\n",
-+ count, buf);
-+ fn();
-+ printk(KERN_INFO "Exec of data @ 0x%p complete\n", buf);
-+ }
-+ return count;
-+}
-+
-+static int smep_test_open(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&smep_test_mutex);
-+ nonseekable_open(inode, file);
-+
-+ if (mutex_lock_interruptible(&smep_test_dev.open_lock)) {
-+ mutex_unlock(&smep_test_mutex);
-+ return -ERESTARTSYS;
-+ }
-+
-+ if (smep_test_dev.opened) {
-+ mutex_unlock(&smep_test_dev.open_lock);
-+ mutex_unlock(&smep_test_mutex);
-+ return -EINVAL;
-+ }
-+
-+ smep_test_dev.opened++;
-+ mutex_unlock(&smep_test_dev.open_lock);
-+ mutex_unlock(&smep_test_mutex);
-+ return 0;
-+}
-+
-+static int smep_test_release(struct inode *inode, struct file *file)
-+{
-+ mutex_lock(&smep_test_dev.open_lock);
-+ smep_test_dev.opened = 0;
-+ mutex_unlock(&smep_test_dev.open_lock);
-+
-+ return 0;
-+}
-+
-+
-+
-+static const struct file_operations smep_test_file_ops = {
-+ .open = smep_test_open,
-+ .release = smep_test_release,
-+ .unlocked_ioctl = smep_test_ioctl,
-+ .write = smep_test_write,
-+ .llseek = no_llseek,
-+};
-+
-+
-+/**
-+ * intel_cln_smep_test_probe
-+ *
-+ * @param pdev: Platform device
-+ * @return 0 success < 0 failure
-+ *
-+ * Callback from platform sub-system to probe
-+ *
-+ * This driver manages eSRAM on a per-page basis. Therefore if we find block
-+ * mode is enabled, or any global, block-level or page-level locks are in place
-+ * at module initialisation time - we bail out.
-+ */
-+static int intel_cln_smep_test_probe(struct platform_device * pdev)
-+{
-+ int retval = 0;
-+ unsigned int minor = 0;
-+
-+ mutex_init(&smep_test_dev.open_lock);
-+ cdev_init(&smep_test_dev.cdev, &smep_test_file_ops);
-+ smep_test_dev.cdev.owner = THIS_MODULE;
-+
-+ retval = cdev_add(&smep_test_dev.cdev, MKDEV(smep_test_major, minor), 1);
-+ if (retval) {
-+ printk(KERN_ERR "chardev registration failed\n");
-+ return -EINVAL;
-+ }
-+ if (IS_ERR(device_create(smep_test_class, NULL,
-+ MKDEV(smep_test_major, minor), NULL,
-+ "smeptest%u", minor))){
-+ dev_err(&pdev->dev, "can't create device\n");
-+ return -EINVAL;
-+ }
-+ printk(KERN_INFO "%s complete OK - device /dev/smeptest%u\n", __FUNCTION__, minor);
-+ return 0;
-+
-+}
-+
-+/**
-+ * intel_cln_smep_remove
-+ *
-+ * @return 0 success < 0 failure
-+ *
-+ * Removes a platform device
-+ */
-+static int intel_cln_smep_test_remove(struct platform_device * pdev)
-+{
-+ unsigned int minor = MINOR(smep_test_dev.cdev.dev);
-+
-+ device_destroy(smep_test_class, MKDEV(smep_test_major, minor));
-+ cdev_del(&smep_test_dev.cdev);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Platform structures useful for interface to PM subsystem
-+ */
-+static struct platform_driver intel_cln_smep_test_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .remove = intel_cln_smep_test_remove,
-+};
-+
-+/**
-+ * intel_cln_smep_init
-+ *
-+ * @return 0 success < 0 failure
-+ *
-+ * Module entry point
-+ */
-+static int __init intel_cln_smep_test_init(void)
-+{
-+ int retval = 0;
-+ dev_t dev;
-+
-+ smep_test_class = class_create(THIS_MODULE,"cln_smep_test");
-+ if (IS_ERR(smep_test_class)) {
-+ retval = PTR_ERR(smep_test_class);
-+ printk(KERN_ERR "smep_test: can't register earam_test class\n");
-+ goto err;
-+ }
-+
-+ retval = alloc_chrdev_region(&dev, 0, 1, "smep_test");
-+ if (retval) {
-+ printk(KERN_ERR "smep_test: can't register character device\n");
-+ goto err_class;
-+ }
-+ smep_test_major = MAJOR(dev);
-+
-+ memset(&smep_test_dev, 0x00, sizeof(smep_test_dev));
-+ smep_test_dev.pldev = platform_create_bundle(
-+ &intel_cln_smep_test_driver, intel_cln_smep_test_probe, NULL, 0, NULL, 0);
-+
-+ if(IS_ERR(smep_test_dev.pldev)){
-+ printk(KERN_ERR "smep_test platform_create_bundle fail!\n");
-+ retval = PTR_ERR(smep_test_dev.pldev);
-+ goto err_class;
-+ }
-+
-+ return 0;
-+
-+err_class:
-+ class_destroy(smep_test_class);
-+err:
-+ return retval;
-+}
-+
-+/**
-+ * intel_cln_smep_exit
-+ *
-+ * Module exit
-+ */
-+static void __exit intel_cln_smep_test_exit(void)
-+{
-+ platform_device_unregister(smep_test_dev.pldev);
-+ platform_driver_unregister(&intel_cln_smep_test_driver);
-+}
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
-+MODULE_DESCRIPTION("Intel Clanton SMEP test");
-+MODULE_LICENSE("Dual BSD/GPL");
-+
-+module_init(intel_cln_smep_test_init);
-+module_exit(intel_cln_smep_test_exit);
-diff --git a/drivers/platform/x86/quark/intel_cln_thermal.c b/drivers/platform/x86/quark/intel_cln_thermal.c
-new file mode 100644
-index 0000000..ce0da9c
---- /dev/null
-+++ b/drivers/platform/x86/quark/intel_cln_thermal.c
-@@ -0,0 +1,360 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton Thermal driver
-+ */
-+#include <linux/err.h>
-+#include <linux/fs.h>
-+#include <linux/intel_cln_sb.h>
-+#include <linux/list.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/printk.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm.h>
-+#include <linux/slab.h>
-+#include <linux/spinlock.h>
-+#include <linux/thermal.h>
-+#include <linux/timer.h>
-+
-+#define DRIVER_NAME "intel-cln-thrm"
-+
-+/* Definition of register locations for thermal management */
-+#define THRM_CTRL_REG (0x80) /* Thermal control */
-+#define THRM_MODE_REG (0xB0) /* Thermal mode */
-+#define THRM_MODE_SENSOR_EN (0x00008000) /* Thermal mode sensor enable */
-+#define THRM_TEMP_REG (0xB1) /* Thermal sensor temperature */
-+#define THRM_TRPCLR_REG (0xB2) /* Catastropic/Hot trip/clear */
-+#define THRM_AUXTRP_REG (0xB3) /* Aux0-Aux3 trip point */
-+#define THRM_AUXCLR_REG (0xB4) /* Aux0-Aux3 clear trip */
-+#define THRM_STATUS_REG (0xB5) /* Thermal sensor status */
-+#define THRM_TRIPBEHAVE_REG (0xB6) /* Trip point behavior */
-+#define THRM_MSIADDR_REG (0xC5) /* Thermal MSI addres reg */
-+#define THRM_MSIDATA_REG (0xC6) /* Thermal MSI data reg */
-+#define THRM_CTRL_READ (0x10) /* Config reg */
-+#define THRM_CTRL_WRITE (0x11) /* Config reg */
-+
-+#define SOC_TSENSOR_REG (0x34)
-+#define SOC_TSENSOR_RST (0x00000001)
-+#define SOC_CTRL_READ (0x06)
-+#define SOC_CTRL_WRITE (0x07)
-+
-+
-+#define THRM_ZONE_COUNT 2 /* Only hot/critical relevant */
-+#define ACTIVE_INTERVAL (1000)
-+#define IDLE_INTERVAL (20000)
-+#define MCELSIUS(x) ((x) * 1000)
-+
-+/* CPU Zone information */
-+#define CATASTROPIC_ZONE 0
-+#define HOT_ZONE 1
-+#define AUX0_ZONE 2 /* Unused */
-+#define AUX1_ZONE 3 /* Unused */
-+#define AUX2_ZONE 4 /* Unused */
-+#define AUX3_ZONE 5 /* Unused */
-+#define MIN_USED_ZONE CATASTROPIC_ZONE
-+#define MAX_USED_ZONE HOT_ZONE
-+/*
-+ * Default catastrophic/hot trip values - in degrees celsius
-+ * Maximum temperature is 105 degrees
-+ */
-+#define CRIT_TEMP 104
-+#define HOT_TEMP 95
-+#define RAW2CELSIUS_DIFF 50
-+
-+static int driver_enable = 1;
-+module_param(driver_enable, int, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(driver_enable, "Disable Thermal Driver Polling");
-+
-+/* Shorten fn names to fit 80 char limit */
-+#ifndef sb_read
-+#define sb_read intel_cln_sb_read_reg
-+#endif
-+#ifndef sb_write
-+#define sb_write intel_cln_sb_write_reg
-+#endif
-+
-+struct intel_cln_therm_zone {
-+ enum thermal_trip_type type;
-+ int trip_value;
-+};
-+
-+/**
-+ * struct intel_cln_thermal_dev
-+ *
-+ */
-+struct intel_cln_thermal_dev {
-+ enum thermal_device_mode mode;
-+ struct intel_cln_therm_zone tzone[THRM_ZONE_COUNT];
-+ struct mutex lock;
-+ struct platform_device *pldev; /* Platform device */
-+ struct thermal_zone_device *therm_dev; /* Thermal device */
-+};
-+
-+static struct intel_cln_thermal_dev cln_tdev;
-+
-+/******************************************************************************
-+ * Thermal API implementation
-+ ******************************************************************************/
-+
-+/**
-+ * get_temp
-+ *
-+ * @param tz: Thermal zone descriptor
-+ *
-+ * Get the current temperature
-+ * We have exactly one thermal zone/sensor
-+ * Value passed is an unsigned long - our sensor reports up to -50 celsius so we
-+ * just clip at zero if the temperature is negative.
-+ */
-+static int intel_cln_thermal_get_temp(struct thermal_zone_device *tz,
-+ unsigned long *temp)
-+{
-+ sb_read(SB_ID_THERMAL, THRM_CTRL_READ, THRM_TEMP_REG, (u32 *)temp, 1);
-+ *temp -= RAW2CELSIUS_DIFF;
-+
-+ /* Clip to unsigned output value if sensor is reporting sub-zero */
-+ if ((int)*temp < 0)
-+ *temp = 0;
-+
-+ *temp = MCELSIUS(*temp&0x000000FF);
-+
-+ return 0;
-+}
-+
-+/**
-+ * get_trend
-+ *
-+ * Wears good clothes
-+ */
-+static int intel_cln_thermal_get_trend(struct thermal_zone_device *tz,
-+ int trip, enum thermal_trend *trend)
-+{
-+ if (tz->temperature >= trip)
-+ *trend = THERMAL_TREND_RAISING;
-+ else
-+ *trend = THERMAL_TREND_DROPPING;
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_thermal_get_mode
-+ *
-+ * Get the mode
-+ */
-+static int intel_cln_thermal_get_mode(struct thermal_zone_device *tz,
-+ enum thermal_device_mode *mode)
-+{
-+ mutex_lock(&cln_tdev.lock);
-+ *mode = cln_tdev.mode;
-+ mutex_unlock(&cln_tdev.lock);
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_thermal_set_mode
-+ *
-+ * Set the mode
-+ */
-+static int intel_cln_thermal_set_mode(struct thermal_zone_device *tz,
-+ enum thermal_device_mode mode)
-+{
-+ mutex_lock(&cln_tdev.lock);
-+
-+ if (mode == THERMAL_DEVICE_ENABLED)
-+ cln_tdev.therm_dev->polling_delay = IDLE_INTERVAL;
-+ else
-+ cln_tdev.therm_dev->polling_delay = 0;
-+ cln_tdev.mode = mode;
-+
-+ mutex_unlock(&cln_tdev.lock);
-+
-+ thermal_zone_device_update(cln_tdev.therm_dev);
-+ pr_info("thermal polling set for duration=%d msec\n",
-+ cln_tdev.therm_dev->polling_delay);
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_thermal_get_trip_type
-+ *
-+ * Get trip type
-+ */
-+static int intel_cln_thermal_get_trip_type(struct thermal_zone_device *tz,
-+ int trip, enum thermal_trip_type *type)
-+{
-+ if (trip < MIN_USED_ZONE || trip > MAX_USED_ZONE)
-+ return -EINVAL;
-+
-+ *type = cln_tdev.tzone[trip].type;
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_thermal_get_trip_temp
-+ *
-+ * Get trip temp
-+ */
-+static int intel_cln_thermal_get_trip_temp(struct thermal_zone_device *tz,
-+ int trip, unsigned long *temp)
-+{
-+ if (trip < MIN_USED_ZONE || trip > MAX_USED_ZONE)
-+ return -EINVAL;
-+
-+ /* Convert the temperature into millicelsius */
-+ *temp = cln_tdev.tzone[trip].trip_value;
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_thermal_get_trip_type
-+ *
-+ * Get trip temp
-+ */
-+static int intel_cln_thermal_get_crit_temp(struct thermal_zone_device *tz,
-+ unsigned long *temp)
-+{
-+ /* Critical zone */
-+ *temp = cln_tdev.tzone[CATASTROPIC_ZONE].trip_value;
-+ return 0;
-+}
-+
-+static struct thermal_zone_device_ops intel_cln_thrm_dev_ops = {
-+ .get_temp = intel_cln_thermal_get_temp,
-+ .get_trend = intel_cln_thermal_get_trend,
-+ .get_mode = intel_cln_thermal_get_mode,
-+ .set_mode = intel_cln_thermal_set_mode,
-+ .get_trip_type = intel_cln_thermal_get_trip_type,
-+ .get_trip_temp = intel_cln_thermal_get_trip_temp,
-+ .get_crit_temp = intel_cln_thermal_get_crit_temp,
-+};
-+
-+
-+
-+/**
-+ * intel_cln_init_zone
-+ *
-+ * Initialise a zone
-+ */
-+static void intel_cln_thermal_init_zone(struct intel_cln_therm_zone *tz,
-+ enum thermal_trip_type type, int trip_value)
-+{
-+ tz->type = type;
-+ tz->trip_value = MCELSIUS(trip_value);
-+}
-+
-+/******************************************************************************
-+ * Module Entry/Exit hooks
-+ ******************************************************************************/
-+
-+/**
-+ * intel_cln_thermal_probe
-+ *
-+ * @param pdev: Platform device
-+ * @return 0 success < 0 failure
-+ *
-+ * Callback from platform sub-system to probe
-+ *
-+ * This routine registers a thermal device with the kernel's thermal management
-+ * sub-system
-+ */
-+static int intel_cln_thermal_probe(struct platform_device *pdev)
-+{
-+ int err = 0;
-+ int critical_temp = 0, hot_temp = 0;
-+ uint32_t regval = 0;
-+
-+ if (driver_enable == 0)
-+ return 0;
-+
-+ memset(&cln_tdev, 0x00, sizeof(cln_tdev));
-+
-+ critical_temp = CRIT_TEMP;
-+ hot_temp = HOT_TEMP;
-+
-+ /* Enumerate zone type data */
-+ memset(&cln_tdev, 0x00, sizeof(cln_tdev));
-+ mutex_init(&cln_tdev.lock);
-+
-+ /* Set initial state disabled */
-+ cln_tdev.mode = THERMAL_DEVICE_ENABLED;
-+
-+ intel_cln_thermal_init_zone(&cln_tdev.tzone[CATASTROPIC_ZONE],
-+ THERMAL_TRIP_CRITICAL, critical_temp);
-+ intel_cln_thermal_init_zone(&cln_tdev.tzone[HOT_ZONE],
-+ THERMAL_TRIP_HOT, hot_temp);
-+
-+ /* Register a thermal zone */
-+ cln_tdev.therm_dev = thermal_zone_device_register(DRIVER_NAME,
-+ THRM_ZONE_COUNT, 0, 0, &intel_cln_thrm_dev_ops,
-+ 0, IDLE_INTERVAL, ACTIVE_INTERVAL);
-+
-+ if (IS_ERR(cln_tdev.therm_dev)) {
-+ err = PTR_ERR(cln_tdev.therm_dev);
-+ return err;
-+ }
-+
-+ /* Read the BIOS configured hardware catastrophic trip temp */
-+ sb_read(SB_ID_THERMAL, THRM_CTRL_READ, THRM_TRPCLR_REG, &regval, 1);
-+ regval = (regval & 0xff) - 50;
-+
-+ pr_info("THRM: critical reset %d c hot %d c hardware failover %d c\n",
-+ critical_temp, hot_temp, regval);
-+
-+ return 0;
-+}
-+
-+/**
-+ * intel_cln_thermal_remove
-+ *
-+ * @return 0 success < 0 failure
-+ *
-+ * Removes a platform device
-+ */
-+static int intel_cln_thermal_remove(struct platform_device *pdev)
-+{
-+ if (cln_tdev.therm_dev != NULL) {
-+ thermal_zone_device_unregister(cln_tdev.therm_dev);
-+ return 0;
-+ }
-+ return -EINVAL;
-+}
-+
-+/*
-+ * Platform structures useful for interface to PM subsystem
-+ */
-+static struct platform_driver intel_cln_thermal_driver = {
-+ .driver = {
-+ .name = DRIVER_NAME,
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = intel_cln_thermal_probe,
-+ .remove = intel_cln_thermal_remove,
-+};
-+
-+module_platform_driver(intel_cln_thermal_driver);
-+
-+
-+MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
-+MODULE_DESCRIPTION("Intel Clanton Thermal driver");
-+MODULE_LICENSE("Dual BSD/GPL");
-diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
-index 8a7cfb3..5deac43 100644
---- a/drivers/power/power_supply_core.c
-+++ b/drivers/power/power_supply_core.c
-@@ -141,7 +141,7 @@ int power_supply_set_battery_charged(struct power_supply *psy)
- }
- EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
-
--static int power_supply_match_device_by_name(struct device *dev, void *data)
-+static int power_supply_match_device_by_name(struct device *dev, const void *data)
- {
- const char *name = data;
- struct power_supply *psy = dev_get_drvdata(dev);
-@@ -149,7 +149,7 @@ static int power_supply_match_device_by_name(struct device *dev, void *data)
- return strcmp(psy->name, name) == 0;
- }
-
--struct power_supply *power_supply_get_by_name(char *name)
-+struct power_supply *power_supply_get_by_name(const char *name)
- {
- struct device *dev = class_find_device(power_supply_class, NULL, name,
- power_supply_match_device_by_name);
-diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
-index e513cd9..03120a8 100644
---- a/drivers/pwm/Kconfig
-+++ b/drivers/pwm/Kconfig
-@@ -28,6 +28,10 @@ menuconfig PWM
-
- if PWM
-
-+config PWM_SYSFS
-+ bool
-+ default y if SYSFS
-+
- config PWM_AB8500
- tristate "AB8500 PWM support"
- depends on AB8500_CORE && ARCH_U8500
-diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
-index 62a2963..f98371b 100644
---- a/drivers/pwm/Makefile
-+++ b/drivers/pwm/Makefile
-@@ -1,4 +1,5 @@
- obj-$(CONFIG_PWM) += core.o
-+obj-$(CONFIG_PWM_SYSFS) += sysfs.o
- obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
- obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
- obj-$(CONFIG_PWM_IMX) += pwm-imx.o
-diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
-index 903138b..bfc8c05 100644
---- a/drivers/pwm/core.c
-+++ b/drivers/pwm/core.c
-@@ -272,6 +272,8 @@ int pwmchip_add(struct pwm_chip *chip)
- if (IS_ENABLED(CONFIG_OF))
- of_pwmchip_add(chip);
-
-+ pwmchip_sysfs_export(chip);
-+
- out:
- mutex_unlock(&pwm_lock);
- return ret;
-@@ -308,6 +310,8 @@ int pwmchip_remove(struct pwm_chip *chip)
-
- free_pwms(chip);
-
-+ pwmchip_sysfs_unexport(chip);
-+
- out:
- mutex_unlock(&pwm_lock);
- return ret;
-@@ -400,10 +404,19 @@ EXPORT_SYMBOL_GPL(pwm_free);
- */
- int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
- {
-+ int err;
-+
- if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
- return -EINVAL;
-
-- return pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
-+ err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
-+ if (err)
-+ return err;
-+
-+ pwm->duty_cycle = duty_ns;
-+ pwm->period = period_ns;
-+
-+ return 0;
- }
- EXPORT_SYMBOL_GPL(pwm_config);
-
-@@ -416,6 +429,8 @@ EXPORT_SYMBOL_GPL(pwm_config);
- */
- int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
- {
-+ int err;
-+
- if (!pwm || !pwm->chip->ops)
- return -EINVAL;
-
-@@ -425,7 +440,13 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
- if (test_bit(PWMF_ENABLED, &pwm->flags))
- return -EBUSY;
-
-- return pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
-+ err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
-+ if (err)
-+ return err;
-+
-+ pwm->polarity = polarity;
-+
-+ return 0;
- }
- EXPORT_SYMBOL_GPL(pwm_set_polarity);
-
-diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
-new file mode 100644
-index 0000000..4cd6d78
---- /dev/null
-+++ b/drivers/pwm/sysfs.c
-@@ -0,0 +1,353 @@
-+/*
-+ * A simple sysfs interface for the generic PWM framework
-+ *
-+ * Copyright (C) 2013 H Hartley Sweeten <hsweeten@visionengravers.com>
-+ *
-+ * Based on previous work by Lars Poeschel <poeschel@lemonage.de>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2, or (at your option)
-+ * any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/export.h>
-+#include <linux/device.h>
-+#include <linux/mutex.h>
-+#include <linux/err.h>
-+#include <linux/slab.h>
-+#include <linux/kdev_t.h>
-+#include <linux/pwm.h>
-+
-+struct pwm_export {
-+ struct device child;
-+ struct pwm_device *pwm;
-+};
-+
-+static struct pwm_export *child_to_pwm_export(struct device *child)
-+{
-+ return container_of(child, struct pwm_export, child);
-+}
-+
-+static struct pwm_device *child_to_pwm_device(struct device *child)
-+{
-+ struct pwm_export *export = child_to_pwm_export(child);
-+
-+ return export->pwm;
-+}
-+
-+static ssize_t pwm_period_show(struct device *child,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ const struct pwm_device *pwm = child_to_pwm_device(child);
-+
-+ return sprintf(buf, "%u\n", pwm->period);
-+}
-+
-+static ssize_t pwm_period_store(struct device *child,
-+ struct device_attribute *attr,
-+ const char *buf, size_t size)
-+{
-+ struct pwm_device *pwm = child_to_pwm_device(child);
-+ unsigned int val;
-+ int ret;
-+
-+ ret = kstrtouint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+
-+ ret = pwm_config(pwm, pwm->duty_cycle, val);
-+
-+ return ret ? : size;
-+}
-+
-+static ssize_t pwm_duty_cycle_show(struct device *child,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ const struct pwm_device *pwm = child_to_pwm_device(child);
-+
-+ return sprintf(buf, "%u\n", pwm->duty_cycle);
-+}
-+
-+static ssize_t pwm_duty_cycle_store(struct device *child,
-+ struct device_attribute *attr,
-+ const char *buf, size_t size)
-+{
-+ struct pwm_device *pwm = child_to_pwm_device(child);
-+ unsigned int val;
-+ int ret;
-+
-+ ret = kstrtouint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+
-+ ret = pwm_config(pwm, val, pwm->period);
-+
-+ return ret ? : size;
-+}
-+
-+static ssize_t pwm_enable_show(struct device *child,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ const struct pwm_device *pwm = child_to_pwm_device(child);
-+ int enabled = test_bit(PWMF_ENABLED, &pwm->flags);
-+
-+ return sprintf(buf, "%d\n", enabled);
-+}
-+
-+static ssize_t pwm_enable_store(struct device *child,
-+ struct device_attribute *attr,
-+ const char *buf, size_t size)
-+{
-+ struct pwm_device *pwm = child_to_pwm_device(child);
-+ int val, ret;
-+
-+ ret = kstrtoint(buf, 0, &val);
-+ if (ret)
-+ return ret;
-+
-+ switch (val) {
-+ case 0:
-+ pwm_disable(pwm);
-+ break;
-+ case 1:
-+ ret = pwm_enable(pwm);
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret ? : size;
-+}
-+
-+static ssize_t pwm_polarity_show(struct device *child,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ const struct pwm_device *pwm = child_to_pwm_device(child);
-+
-+ return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal");
-+}
-+
-+static ssize_t pwm_polarity_store(struct device *child,
-+ struct device_attribute *attr,
-+ const char *buf, size_t size)
-+{
-+ struct pwm_device *pwm = child_to_pwm_device(child);
-+ enum pwm_polarity polarity;
-+ int ret;
-+
-+ if (sysfs_streq(buf, "normal"))
-+ polarity = PWM_POLARITY_NORMAL;
-+ else if (sysfs_streq(buf, "inversed"))
-+ polarity = PWM_POLARITY_INVERSED;
-+ else
-+ return -EINVAL;
-+
-+ ret = pwm_set_polarity(pwm, polarity);
-+
-+ return ret ? : size;
-+}
-+
-+static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store);
-+static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store);
-+static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store);
-+static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store);
-+
-+static struct attribute *pwm_attrs[] = {
-+ &dev_attr_period.attr,
-+ &dev_attr_duty_cycle.attr,
-+ &dev_attr_enable.attr,
-+ &dev_attr_polarity.attr,
-+ NULL
-+};
-+
-+static const struct attribute_group pwm_attr_group = {
-+ .attrs = pwm_attrs,
-+};
-+
-+static const struct attribute_group *pwm_attr_groups[] = {
-+ &pwm_attr_group,
-+ NULL,
-+};
-+
-+static void pwm_export_release(struct device *child)
-+{
-+ struct pwm_export *export = child_to_pwm_export(child);
-+
-+ kfree(export);
-+}
-+
-+static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
-+{
-+ struct pwm_export *export;
-+ int ret;
-+
-+ if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags))
-+ return -EBUSY;
-+
-+ export = kzalloc(sizeof(*export), GFP_KERNEL);
-+ if (!export) {
-+ clear_bit(PWMF_EXPORTED, &pwm->flags);
-+ return -ENOMEM;
-+ }
-+
-+ export->pwm = pwm;
-+
-+ export->child.release = pwm_export_release;
-+ export->child.parent = parent;
-+ export->child.devt = MKDEV(0, 0);
-+ export->child.groups = pwm_attr_groups;
-+ dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
-+
-+ ret = device_register(&export->child);
-+ if (ret) {
-+ clear_bit(PWMF_EXPORTED, &pwm->flags);
-+ kfree(export);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int pwm_unexport_match(struct device *child, void *data)
-+{
-+ return child_to_pwm_device(child) == data;
-+}
-+
-+static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
-+{
-+ struct device *child;
-+
-+ if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags))
-+ return -ENODEV;
-+
-+ child = device_find_child(parent, pwm, pwm_unexport_match);
-+ if (!child)
-+ return -ENODEV;
-+
-+ /* for device_find_child() */
-+ put_device(child);
-+ device_unregister(child);
-+ pwm_put(pwm);
-+
-+ return 0;
-+}
-+
-+static ssize_t pwm_export_store(struct device *parent,
-+ struct device_attribute *attr,
-+ const char *buf, size_t len)
-+{
-+ struct pwm_chip *chip = dev_get_drvdata(parent);
-+ struct pwm_device *pwm;
-+ unsigned int hwpwm;
-+ int ret;
-+
-+ ret = kstrtouint(buf, 0, &hwpwm);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (hwpwm >= chip->npwm)
-+ return -ENODEV;
-+
-+ pwm = pwm_request_from_chip(chip, hwpwm, "sysfs");
-+ if (IS_ERR(pwm))
-+ return PTR_ERR(pwm);
-+
-+ ret = pwm_export_child(parent, pwm);
-+ if (ret < 0)
-+ pwm_put(pwm);
-+
-+ return ret ? : len;
-+}
-+
-+static ssize_t pwm_unexport_store(struct device *parent,
-+ struct device_attribute *attr,
-+ const char *buf, size_t len)
-+{
-+ struct pwm_chip *chip = dev_get_drvdata(parent);
-+ unsigned int hwpwm;
-+ int ret;
-+
-+ ret = kstrtouint(buf, 0, &hwpwm);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (hwpwm >= chip->npwm)
-+ return -ENODEV;
-+
-+ ret = pwm_unexport_child(parent, &chip->pwms[hwpwm]);
-+
-+ return ret ? : len;
-+}
-+
-+static ssize_t pwm_npwm_show(struct device *parent,
-+ struct device_attribute *attr,
-+ char *buf)
-+{
-+ const struct pwm_chip *chip = dev_get_drvdata(parent);
-+
-+ return sprintf(buf, "%u\n", chip->npwm);
-+}
-+
-+static struct device_attribute pwm_chip_attrs[] = {
-+ __ATTR(export, 0200, NULL, pwm_export_store),
-+ __ATTR(unexport, 0200, NULL, pwm_unexport_store),
-+ __ATTR(npwm, 0444, pwm_npwm_show, NULL),
-+ __ATTR_NULL,
-+};
-+
-+static struct class pwm_class = {
-+ .name = "pwm",
-+ .owner = THIS_MODULE,
-+ .dev_attrs = pwm_chip_attrs,
-+};
-+
-+static int pwmchip_sysfs_match(struct device *parent, const void *data)
-+{
-+ return dev_get_drvdata(parent) == data;
-+}
-+
-+void pwmchip_sysfs_export(struct pwm_chip *chip)
-+{
-+ struct device *parent;
-+
-+ /*
-+ * If device_create() fails the pwm_chip is still usable by
-+ * the kernel its just not exported.
-+ */
-+ parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
-+ "pwmchip%d", chip->base);
-+ if (IS_ERR(parent)) {
-+ dev_warn(chip->dev,
-+ "device_create failed for pwm_chip sysfs export\n");
-+ }
-+}
-+
-+void pwmchip_sysfs_unexport(struct pwm_chip *chip)
-+{
-+ struct device *parent;
-+
-+ parent = class_find_device(&pwm_class, NULL, chip,
-+ pwmchip_sysfs_match);
-+ if (parent) {
-+ /* for class_find_device() */
-+ put_device(parent);
-+ device_unregister(parent);
-+ }
-+}
-+
-+static int __init pwm_sysfs_init(void)
-+{
-+ return class_register(&pwm_class);
-+}
-+subsys_initcall(pwm_sysfs_init);
-diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
-index 9592b93..42bd57d 100644
---- a/drivers/rtc/interface.c
-+++ b/drivers/rtc/interface.c
-@@ -587,16 +587,16 @@ void rtc_update_irq(struct rtc_device *rtc,
- }
- EXPORT_SYMBOL_GPL(rtc_update_irq);
-
--static int __rtc_match(struct device *dev, void *data)
-+static int __rtc_match(struct device *dev, const void *data)
- {
-- char *name = (char *)data;
-+ const char *name = data;
-
- if (strcmp(dev_name(dev), name) == 0)
- return 1;
- return 0;
- }
-
--struct rtc_device *rtc_class_open(char *name)
-+struct rtc_device *rtc_class_open(const char *name)
- {
- struct device *dev;
- struct rtc_device *rtc = NULL;
-diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
-index 593085a..df0c3c7 100644
---- a/drivers/scsi/hosts.c
-+++ b/drivers/scsi/hosts.c
-@@ -468,10 +468,10 @@ void scsi_unregister(struct Scsi_Host *shost)
- }
- EXPORT_SYMBOL(scsi_unregister);
-
--static int __scsi_host_match(struct device *dev, void *data)
-+static int __scsi_host_match(struct device *dev, const void *data)
- {
- struct Scsi_Host *p;
-- unsigned short *hostnum = (unsigned short *)data;
-+ const unsigned short *hostnum = data;
-
- p = class_to_shost(dev);
- return p->host_no == *hostnum;
-diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
-index 4375417..0fab6b5 100644
---- a/drivers/scsi/osd/osd_uld.c
-+++ b/drivers/scsi/osd/osd_uld.c
-@@ -268,18 +268,11 @@ static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len,
- return 0 == memcmp(a1, a2, a1_len);
- }
-
--struct find_oud_t {
-- const struct osd_dev_info *odi;
-- struct device *dev;
-- struct osd_uld_device *oud;
--} ;
--
--int _mach_odi(struct device *dev, void *find_data)
-+static int _match_odi(struct device *dev, const void *find_data)
- {
- struct osd_uld_device *oud = container_of(dev, struct osd_uld_device,
- class_dev);
-- struct find_oud_t *fot = find_data;
-- const struct osd_dev_info *odi = fot->odi;
-+ const struct osd_dev_info *odi = find_data;
-
- if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len,
- odi->systemid, odi->systemid_len) &&
-@@ -287,7 +280,6 @@ int _mach_odi(struct device *dev, void *find_data)
- odi->osdname, odi->osdname_len)) {
- OSD_DEBUG("found device sysid_len=%d osdname=%d\n",
- odi->systemid_len, odi->osdname_len);
-- fot->oud = oud;
- return 1;
- } else {
- return 0;
-@@ -301,19 +293,19 @@ int _mach_odi(struct device *dev, void *find_data)
- */
- struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi)
- {
-- struct find_oud_t find = {.odi = odi};
--
-- find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi);
-- if (likely(find.dev)) {
-+ struct device *dev = class_find_device(&osd_uld_class, NULL, odi, _match_odi);
-+ if (likely(dev)) {
- struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL);
-+ struct osd_uld_device *oud = container_of(dev,
-+ struct osd_uld_device, class_dev);
-
- if (unlikely(!odh)) {
-- put_device(find.dev);
-+ put_device(dev);
- return ERR_PTR(-ENOMEM);
- }
-
-- odh->od = find.oud->od;
-- odh->oud = find.oud;
-+ odh->od = oud->od;
-+ odh->oud = oud;
-
- return &odh->od;
- }
-diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
-index 31969f2..59d427b 100644
---- a/drivers/scsi/scsi_transport_iscsi.c
-+++ b/drivers/scsi/scsi_transport_iscsi.c
-@@ -183,10 +183,10 @@ static struct attribute_group iscsi_endpoint_group = {
-
- #define ISCSI_MAX_EPID -1
-
--static int iscsi_match_epid(struct device *dev, void *data)
-+static int iscsi_match_epid(struct device *dev, const void *data)
- {
- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
-- uint64_t *epid = (uint64_t *) data;
-+ const uint64_t *epid = data;
-
- return *epid == ep->id;
- }
-diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
-index 2e188e1..5043dc4 100644
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -35,6 +35,14 @@ config SPI_DEBUG
- Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
- sysfs, and debugfs support in SPI controller and protocol drivers.
-
-+config GEN3_SPI
-+ bool "Intel Media SOC SPI support"
-+ depends on SPI && ARCH_GEN3 && INTEL_QUARK_X1000_SOC
-+ default y
-+ help
-+ This option enables Intel Media SOC SPI support.
-+ For Clanton this option depends on INTEL_QUARK_X1000_SOC.
-+
- #
- # MASTER side ... talking to discrete SPI slave chips including microcontrollers
- #
-@@ -74,7 +82,15 @@ config SPI_ATMEL
- This selects a driver for the Atmel SPI Controller, present on
- many AT32 (AVR32) and AT91 (ARM) chips.
-
--config SPI_BFIN5XX
-+config SPI_CE5XX_SPI_FLASH
-+ tristate "CE5XX SPI FLASH"
-+ depends on ARCH_GEN3 && HW_MUTEXES
-+ default y
-+ help
-+ This selects a driver for CE5XX Serial Flash controler
-+
-+
-+config SPI_BFIN
- tristate "SPI controller driver for ADI Blackfin5xx"
- depends on BLACKFIN
- help
-@@ -302,12 +318,21 @@ config SPI_PXA2XX
- depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
- select PXA_SSP if ARCH_PXA
- help
-- This enables using a PXA2xx or Sodaville SSP port as a SPI master
-+ This enables using a PXA2xx or Intel CE4100/CE4200/CE5300 port as a SPI master
- controller. The driver can be configured to use any SSP port and
- additional documentation can be found a Documentation/spi/pxa2xx.
-
- config SPI_PXA2XX_PCI
-- def_bool SPI_PXA2XX && X86_32 && PCI
-+ tristate "Intel CE SPI PCI adapter"
-+ depends on SPI_PXA2XX && X86_32 && PCI && GEN3_SPI
-+ help
-+ This driver supports the Intel CE SPI master controller and acts
-+ as the PCI-SPI glue code for PXA's driver
-+
-+config SPI_CE5XX_SPI_SLAVE
-+ tristate "CE5XX SPI SLAVE"
-+ help
-+ This selects a driver for CE5XX SPI Slave controler, it is emudulated into a spi device
-
- config SPI_RSPI
- tristate "Renesas RSPI controller"
-@@ -471,6 +496,14 @@ config SPI_DW_MMIO
- depends on SPI_DESIGNWARE && HAVE_CLK
-
- #
-+# Bring out the LPC_SCH SPI block
-+#
-+
-+config SPI_LPC_SCH
-+ tristate "LPC SCH Legacy SPI controller"
-+ depends on LPC_SCH
-+
-+#
- # There are lots of SPI device types, with sensors and memory
- # being probably the most widely used ones.
- #
-diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
-index 64e970b..b67de97 100644
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -26,6 +26,7 @@ obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
- obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
- obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
- spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
-+obj-$(CONFIG_SPI_LPC_SCH) += spi-lpc-sch.o
- obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
- obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
- obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
-diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
-index c7cf0b7..0fa345c 100644
---- a/drivers/spi/spi-gpio.c
-+++ b/drivers/spi/spi-gpio.c
-@@ -265,9 +265,9 @@ static int spi_gpio_setup(struct spi_device *spi)
- }
- }
- if (!status) {
-- status = spi_bitbang_setup(spi);
- /* in case it was initialized from static board data */
- spi_gpio->cs_gpios[spi->chip_select] = cs;
-+ status = spi_bitbang_setup(spi);
- }
-
- if (status) {
-diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
-index cf95587..7292888 100644
---- a/drivers/spi/spi-pxa2xx-pci.c
-+++ b/drivers/spi/spi-pxa2xx-pci.c
-@@ -7,6 +7,47 @@
- #include <linux/of_device.h>
- #include <linux/module.h>
- #include <linux/spi/pxa2xx_spi.h>
-+#include <linux/irq.h>
-+#include <linux/platform_data/clanton.h>
-+
-+/* defined here to avoid including arch/x86/pci/intel_media_proc_gen3.c */
-+#define CE3100_SOC_DEVICE_ID 0x2E50
-+#define CE4100_SOC_DEVICE_ID 0x0708
-+#define CE4200_SOC_DEVICE_ID 0x0709
-+#define CE5300_SOC_DEVICE_ID 0x0C40
-+#define CE2600_SOC_DEVICE_ID 0x0931
-+
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
-+#define CE4200_NUM_SPI_MASTER 1
-+#else
-+#define CE4200_NUM_SPI_MASTER 2
-+#endif
-+
-+#define CE4X00_SPI_MAX_SPEED 1843200
-+
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+#define CE4200_NUM_CHIPSELECT 2
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
-+#define CE5X00_SPI_MAX_SPEED 3500000
-+#else
-+#define CE5X00_SPI_MAX_SPEED 50000000
-+#endif
-+#else
-+#define CE4200_NUM_CHIPSELECT 4
-+#define CE5X00_SPI_MAX_SPEED 5000000
-+#endif
-+
-+#define SPI_CE_DEBUG
-+
-+static int interface;
-+
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+static int enable_msi = 1;
-+#else
-+static int enable_msi;
-+#endif
-+module_param(enable_msi, int, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
-
- struct ce4100_info {
- struct ssp_device ssp;
-@@ -57,10 +98,11 @@ static int ce4100_spi_probe(struct pci_dev *dev,
- int ret;
- resource_size_t phys_beg;
- resource_size_t phys_len;
-- struct ce4100_info *spi_info;
-+ struct ce4100_info *spi_info = NULL;
- struct platform_device *pdev;
- struct pxa2xx_spi_master spi_pdata;
- struct ssp_device *ssp;
-+ unsigned int id;
-
- ret = pci_enable_device(dev);
- if (ret)
-@@ -77,42 +119,75 @@ static int ce4100_spi_probe(struct pci_dev *dev,
- }
-
- pdev = platform_device_alloc("pxa2xx-spi", dev->devfn);
-+ if (!pdev) {
-+ ret = -ENOMEM;
-+ goto err_release_mem_region;
-+ }
- spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
-- if (!pdev || !spi_info ) {
-+ if (!spi_info) {
- ret = -ENOMEM;
-- goto err_nomem;
-+ goto err_platform_device_put;
- }
- memset(&spi_pdata, 0, sizeof(spi_pdata));
-- spi_pdata.num_chipselect = dev->devfn;
-+ spi_pdata.num_chipselect = CE4200_NUM_CHIPSELECT;
-
- ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata));
- if (ret)
-- goto err_nomem;
-+ goto err_free_spi_info;
-
-+ pdev->id = interface;
- pdev->dev.parent = &dev->dev;
-+#ifdef CONFIG_OF
- pdev->dev.of_node = dev->dev.of_node;
-+#endif
- ssp = &spi_info->ssp;
-+ ssp->pcidev = dev;
- ssp->phys_base = pci_resource_start(dev, 0);
- ssp->mmio_base = ioremap(phys_beg, phys_len);
- if (!ssp->mmio_base) {
- dev_err(&pdev->dev, "failed to ioremap() registers\n");
- ret = -EIO;
-- goto err_nomem;
-+ goto err_ioremap;
-+ }
-+ pci_set_master(dev);
-+ if (enable_msi == 1) {
-+ ret = pci_enable_msi(dev);
-+ if (ret) {
-+ dev_err(&dev->dev, "failed to allocate MSI entry\n");
-+ goto err_dev_add;
-+ }
- }
-+
- ssp->irq = dev->irq;
- ssp->port_id = pdev->id;
-- ssp->type = PXA25x_SSP;
-
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ id = CE5300_SOC_DEVICE_ID;
-+#else
-+ intelce_get_soc_info(&id, NULL);
-+#endif
-+ switch (id) {
-+ case CE5300_SOC_DEVICE_ID:
-+ ssp->type = CE5X00_SSP;
-+ break;
-+ case CE4200_SOC_DEVICE_ID:
-+ default:
-+ ssp->type = CE4100_SSP;
-+ break;
-+ }
- mutex_lock(&ssp_lock);
- list_add(&ssp->node, &ssp_list);
- mutex_unlock(&ssp_lock);
-
- pci_set_drvdata(dev, spi_info);
-
-+ spi_info->spi_pdev = pdev;
- ret = platform_device_add(pdev);
- if (ret)
- goto err_dev_add;
-
-+ interface++;
-+
- return ret;
-
- err_dev_add:
-@@ -121,11 +196,16 @@ err_dev_add:
- list_del(&ssp->node);
- mutex_unlock(&ssp_lock);
- iounmap(ssp->mmio_base);
-+err_ioremap:
-
--err_nomem:
-- release_mem_region(phys_beg, phys_len);
-- platform_device_put(pdev);
-+err_free_spi_info:
- kfree(spi_info);
-+
-+err_platform_device_put:
-+ platform_device_put(pdev);
-+
-+err_release_mem_region:
-+ release_mem_region(phys_beg, phys_len);
- return ret;
- }
-
-@@ -146,21 +226,50 @@ static void ce4100_spi_remove(struct pci_dev *dev)
- list_del(&ssp->node);
- mutex_unlock(&ssp_lock);
-
-+ if (enable_msi == 1) {
-+ if (pci_dev_msi_enabled(dev))
-+ pci_disable_msi(dev);
-+ }
-+
- pci_set_drvdata(dev, NULL);
- pci_disable_device(dev);
- kfree(spi_info);
- }
-
-+
-+#ifdef CONFIG_PM
-+static int ce4XXX_spi_suspend(struct pci_dev *dev, pm_message_t state)
-+{
-+ pci_save_state(dev);
-+ pci_set_power_state(dev, pci_choose_state(dev, state));
-+ return 0;
-+}
-+
-+static int ce4XXX_spi_resume(struct pci_dev *dev)
-+{
-+ pci_set_power_state(dev, PCI_D0);
-+ pci_restore_state(dev);
-+
-+ return 0;
-+}
-+#endif
-+
- static DEFINE_PCI_DEVICE_TABLE(ce4100_spi_devices) = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
-+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0935) },
- { },
- };
-+
- MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
-
- static struct pci_driver ce4100_spi_driver = {
- .name = "ce4100_spi",
- .id_table = ce4100_spi_devices,
- .probe = ce4100_spi_probe,
-+#ifdef CONFIG_PM
-+ .suspend = ce4XXX_spi_suspend,
-+ .resume = ce4XXX_spi_resume,
-+#endif
- .remove = ce4100_spi_remove,
- };
-
-diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
-index 5c8c4f5..125e76a 100644
---- a/drivers/spi/spi-pxa2xx.c
-+++ b/drivers/spi/spi-pxa2xx.c
-@@ -26,14 +26,18 @@
- #include <linux/spi/pxa2xx_spi.h>
- #include <linux/dma-mapping.h>
- #include <linux/spi/spi.h>
--#include <linux/workqueue.h>
- #include <linux/delay.h>
-+#include <linux/clk.h>
- #include <linux/gpio.h>
- #include <linux/slab.h>
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+#include <linux/pm_runtime.h>
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+#include <asm/cln.h>
-+#endif
-
--#include <asm/io.h>
- #include <asm/irq.h>
--#include <asm/delay.h>
-
-
- MODULE_AUTHOR("Stephen Street");
-@@ -51,6 +55,9 @@ MODULE_ALIAS("platform:pxa2xx-spi");
- #define MAX_DMA_LEN 8191
- #define DMA_ALIGNMENT 8
-
-+#define CE5X00_FIFO_DEPTH 32
-+#define CE4X00_FIFO_DEPTH 4
-+
- /*
- * for testing SSCR1 changes that require SSP restart, basically
- * everything except the service and interrupt enables, the pxa270 developer
-@@ -59,35 +66,144 @@ MODULE_ALIAS("platform:pxa2xx-spi");
- * service and interrupt enables
- */
- #define SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
-- | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
-- | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
-- | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
-- | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
-- | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
--
--#define DEFINE_SSP_REG(reg, off) \
--static inline u32 read_##reg(void const __iomem *p) \
--{ return __raw_readl(p + (off)); } \
--\
--static inline void write_##reg(u32 v, void __iomem *p) \
--{ __raw_writel(v, p + (off)); }
--
--DEFINE_SSP_REG(SSCR0, 0x00)
--DEFINE_SSP_REG(SSCR1, 0x04)
--DEFINE_SSP_REG(SSSR, 0x08)
--DEFINE_SSP_REG(SSITR, 0x0c)
--DEFINE_SSP_REG(SSDR, 0x10)
--DEFINE_SSP_REG(SSTO, 0x28)
--DEFINE_SSP_REG(SSPSP, 0x2c)
--
--#define START_STATE ((void*)0)
--#define RUNNING_STATE ((void*)1)
--#define DONE_STATE ((void*)2)
--#define ERROR_STATE ((void*)-1)
-+ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
-+ | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
-+ | SSCR1_IFS | SSCR1_STRF | SSCR1_EFWR \
-+ | SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
-+ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
-+
-+#define CE5X00_SSCR1_CHANGE_MASK (SSCR1_TTELP | SSCR1_TTE | SSCR1_SCFR \
-+ | SSCR1_ECRA | SSCR1_ECRB | SSCR1_SCLKDIR \
-+ | SSCR1_SFRMDIR | SSCR1_RWOT | SSCR1_TRAIL \
-+ | SSCR1_IFS | CE5X00_SSCR1_STRF \
-+ | CE5X00_SSCR1_EFWR \
-+ | CE5X00_SSCR1_RFT | CE5X00_SSCR1_TFT \
-+ | SSCR1_MWDS \
-+ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
-+
-+
-+#define DEFINE_SSP_REG(reg, off) \
-+ static inline u32 read_##reg(void const __iomem *p) \
-+ { return __raw_readl(p + (off)); } \
-+ \
-+ static inline void write_##reg(u32 v, void __iomem *p) \
-+ { __raw_writel(v, p + (off)); }
-+
-+DEFINE_SSP_REG(sscr0, 0x00)
-+DEFINE_SSP_REG(sscr1, 0x04)
-+DEFINE_SSP_REG(sssr, 0x08)
-+DEFINE_SSP_REG(ssitr, 0x0c)
-+DEFINE_SSP_REG(ssdr, 0x10)
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+DEFINE_SSP_REG(dds_rate, 0x28) /* SSTO unused for clanton */
-+#endif
-+DEFINE_SSP_REG(ssto, 0x28)
-+DEFINE_SSP_REG(sspsp, 0x2c)
-+
-+#define START_STATE ((void *)0)
-+#define RUNNING_STATE ((void *)1)
-+#define DONE_STATE ((void *)2)
-+#define ERROR_STATE ((void *)-1)
-
- #define QUEUE_RUNNING 0
- #define QUEUE_STOPPED 1
-
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+#define DDS_MAX 0x800000
-+#define DDS_666666 0x666666
-+#define DDS_400000 0x400000
-+#define DDS_200000 0x200000
-+#define DDS_100000 0x100000
-+#define DDS_80000 0x80000
-+#define DDS_40000 0x40000
-+#define DDS_20000 0x20000
-+#define DDS_10000 0x10000
-+#define DDS_8000 0x8000
-+
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU)
-+/* these values are different on emulations where system clock is 14mhz */
-+#define FSYS 14 /* mhz */
-+#define BITRATE_50MHZ 3500000
-+#define BITRATE_40MHZ 2800000
-+#define BITRATE_25MHZ 1750000
-+#define BITRATE_20MHZ 1400000
-+#define BITRATE_16667KHZ 1167000
-+#define BITRATE_13333KHZ 933000
-+#define BITRATE_12500KHZ 875000
-+#define BITRATE_10MHZ 700000
-+#define BITRATE_8MHZ 560000
-+#define BITRATE_6250KHZ 438000
-+#define BITRATE_5MHZ 350000
-+#define BITRATE_4MHZ 280000
-+#define BITRATE_3125KHZ 219000
-+#define BITRATE_2500KHZ 175000
-+#define BITRATE_2MHZ 140000
-+#define BITRATE_1563KHZ 109000
-+#define BITRATE_1250KHZ 88000
-+#define BITRATE_1MHZ 70000
-+#define BITRATE_800KHZ 56000
-+#define BITRATE_781KHZ 54688
-+#define BITRATE_625KHZ 43750
-+#define BITRATE_500KHZ 35000
-+#define BITRATE_400KHZ 28000
-+#define BITRATE_390KHZ 27344
-+#define BITRATE_250KHZ 17500
-+#define BITRATE_200KHZ 14000
-+#define BITRATE_195KHZ 13672
-+#define BITRATE_125KHZ 8750
-+#define BITRATE_100KHZ 7000
-+#define BITRATE_50KHZ 3500
-+#define BITRATE_25KHZ 1750
-+#define BITRATE_10KHZ 701
-+#define BITRATE_5KHZ 353
-+#define BITRATE_1KHZ 70
-+#define BITRATE_MAX BITRATE_50MHZ
-+#define BITRATE_MIN BITRATE_1KHZ
-+
-+#else
-+
-+#define BITRATE_50MHZ 50000000
-+#define BITRATE_40MHZ 40000000
-+#define BITRATE_25MHZ 25000000
-+#define BITRATE_20MHZ 20000000
-+#define BITRATE_16667KHZ 16667000
-+#define BITRATE_13333KHZ 13333000
-+#define BITRATE_12500KHZ 12500000
-+#define BITRATE_10MHZ 10000000
-+#define BITRATE_8MHZ 8000000
-+#define BITRATE_6250KHZ 6250000
-+#define BITRATE_5MHZ 5000000
-+#define BITRATE_4MHZ 4000000
-+#define BITRATE_3125KHZ 3125000
-+#define BITRATE_2500KHZ 2500000
-+#define BITRATE_2MHZ 2000000
-+#define BITRATE_1563KHZ 1563000
-+#define BITRATE_1250KHZ 1250000
-+#define BITRATE_1MHZ 1000000
-+#define BITRATE_800KHZ 800000
-+#define BITRATE_781KHZ 781250
-+#define BITRATE_625KHZ 625000
-+#define BITRATE_500KHZ 500000
-+#define BITRATE_400KHZ 400000
-+#define BITRATE_390KHZ 390625
-+#define BITRATE_250KHZ 250000
-+#define BITRATE_200KHZ 200000
-+#define BITRATE_195KHZ 195313
-+#define BITRATE_125KHZ 125000
-+#define BITRATE_100KHZ 100000
-+#define BITRATE_50KHZ 50000
-+#define BITRATE_25KHZ 25000
-+#define BITRATE_10KHZ 10016
-+#define BITRATE_5KHZ 5040
-+#define BITRATE_1KHZ 1000
-+#define BITRATE_MIN BITRATE_1KHZ
-+#define BITRATE_MAX BITRATE_50MHZ
-+#define FSYS 200 /* mhz */
-+
-+#endif /* #if defined(CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU) */
-+
-+#endif /* CONFIG_INTEL_QUARK_X1000_SOC */
-+
- struct driver_data {
- /* Driver model hookup */
- struct platform_device *pdev;
-@@ -117,20 +233,12 @@ struct driver_data {
- u32 clear_sr;
- u32 mask_sr;
-
-- /* Driver message queue */
-- struct workqueue_struct *workqueue;
-- struct work_struct pump_messages;
-- spinlock_t lock;
-- struct list_head queue;
-- int busy;
-- int run;
--
-- /* Message Transfer pump */
-+ /* Message per-transfer pump */
- struct tasklet_struct pump_transfers;
-
- /* Current message transfer state info */
-- struct spi_message* cur_msg;
-- struct spi_transfer* cur_transfer;
-+ struct spi_message *cur_msg;
-+ struct spi_transfer *cur_transfer;
- struct chip_data *cur_chip;
- size_t len;
- void *tx;
-@@ -153,6 +261,9 @@ struct driver_data {
- struct chip_data {
- u32 cr0;
- u32 cr1;
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ u32 dds_rate;
-+#endif
- u32 psp;
- u32 timeout;
- u8 n_bytes;
-@@ -173,14 +284,14 @@ struct chip_data {
- void (*cs_control)(u32 command);
- };
-
--static void pump_messages(struct work_struct *work);
--
- static void cs_assert(struct driver_data *drv_data)
- {
- struct chip_data *chip = drv_data->cur_chip;
-
-- if (drv_data->ssp_type == CE4100_SSP) {
-- write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
-+ if (drv_data->ssp_type == CE4100_SSP ||
-+ (drv_data->ssp_type == CE5X00_SSP &&
-+ (!gpio_is_valid(chip->gpio_cs)))) {
-+ write_sssr(drv_data->cur_chip->frm, drv_data->ioaddr);
- return;
- }
-
-@@ -197,9 +308,11 @@ static void cs_deassert(struct driver_data *drv_data)
- {
- struct chip_data *chip = drv_data->cur_chip;
-
-- if (drv_data->ssp_type == CE4100_SSP)
-+ if (drv_data->ssp_type == CE4100_SSP ||
-+ (drv_data->ssp_type == CE5X00_SSP
-+ && (!gpio_is_valid(chip->gpio_cs)))) {
- return;
--
-+ }
- if (chip->cs_control) {
- chip->cs_control(PXA2XX_CS_DEASSERT);
- return;
-@@ -209,14 +322,15 @@ static void cs_deassert(struct driver_data *drv_data)
- gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
- }
-
--static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
-+static void write_sssr_cs(struct driver_data *drv_data, u32 val)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- if (drv_data->ssp_type == CE4100_SSP)
-- val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
-+ if (drv_data->ssp_type == CE4100_SSP
-+ || drv_data->ssp_type == CE5X00_SSP)
-+ val |= read_sssr(reg) & SSSR_ALT_FRM_MASK;
-
-- write_SSSR(val, reg);
-+ write_sssr(val, reg);
- }
-
- static int pxa25x_ssp_comp(struct driver_data *drv_data)
-@@ -225,6 +339,10 @@ static int pxa25x_ssp_comp(struct driver_data *drv_data)
- return 1;
- if (drv_data->ssp_type == CE4100_SSP)
- return 1;
-+#ifdef CONFIG_GEN3_SPI
-+ if (drv_data->ssp_type == CE5X00_SSP)
-+ return 2;
-+#endif
- return 0;
- }
-
-@@ -235,25 +353,46 @@ static int flush(struct driver_data *drv_data)
- void __iomem *reg = drv_data->ioaddr;
-
- do {
-- while (read_SSSR(reg) & SSSR_RNE) {
-- read_SSDR(reg);
-- }
-- } while ((read_SSSR(reg) & SSSR_BSY) && --limit);
-- write_SSSR_CS(drv_data, SSSR_ROR);
-+ while (read_sssr(reg) & SSSR_RNE)
-+ read_ssdr(reg);
-+ } while ((read_sssr(reg) & SSSR_BSY) && --limit);
-+ write_sssr_cs(drv_data, SSSR_ROR);
-
- return limit;
- }
-
-+#ifdef CONFIG_GEN3_SPI
-+static void wait_till_not_busy(struct driver_data *drv_data)
-+{
-+ /*
-+ * Most cases, the BSY bit will be cleared in very short time.
-+ * But if the controller is set to the slowest speed, the BSY
-+ * bit waitting time will increase a lot.
-+ * Here, we set the wait time to 100ms is to deal with such corner case,
-+ * but in real world, there is almost no one will use the slowest
-+ * speed to transfer data, which means there is no need to add more
-+ * complex code to to deal with the slowest speed case.
-+ */
-+ unsigned long end = jiffies + 1 + usecs_to_jiffies(100000);
-+ void __iomem *reg = drv_data->ioaddr;
-+ while (time_before(jiffies, end)) {
-+ if (!(read_sssr(reg) & SSSR_BSY))
-+ return;
-+ }
-+ pr_err("SPI MASTER keeps busy for 100ms after a read/write!\n");
-+}
-+#endif
-+
- static int null_writer(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
- u8 n_bytes = drv_data->n_bytes;
-
-- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
-- || (drv_data->tx == drv_data->tx_end))
-+ if ((!(read_sssr(reg) & SSSR_TNF))
-+ || (drv_data->tx == drv_data->tx_end))
- return 0;
-
-- write_SSDR(0, reg);
-+ write_ssdr(0, reg);
- drv_data->tx += n_bytes;
-
- return 1;
-@@ -264,9 +403,9 @@ static int null_reader(struct driver_data *drv_data)
- void __iomem *reg = drv_data->ioaddr;
- u8 n_bytes = drv_data->n_bytes;
-
-- while ((read_SSSR(reg) & SSSR_RNE)
-+ while ((read_sssr(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
-- read_SSDR(reg);
-+ read_ssdr(reg);
- drv_data->rx += n_bytes;
- }
-
-@@ -277,11 +416,11 @@ static int u8_writer(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
-- || (drv_data->tx == drv_data->tx_end))
-+ if ((!(read_sssr(reg) & SSSR_TNF))
-+ || (drv_data->tx == drv_data->tx_end))
- return 0;
-
-- write_SSDR(*(u8 *)(drv_data->tx), reg);
-+ write_ssdr(*(u8 *)(drv_data->tx), reg);
- ++drv_data->tx;
-
- return 1;
-@@ -291,9 +430,9 @@ static int u8_reader(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- while ((read_SSSR(reg) & SSSR_RNE)
-- && (drv_data->rx < drv_data->rx_end)) {
-- *(u8 *)(drv_data->rx) = read_SSDR(reg);
-+ while ((read_sssr(reg) & SSSR_RNE)
-+ && (drv_data->rx < drv_data->rx_end)) {
-+ *(u8 *)(drv_data->rx) = read_ssdr(reg);
- ++drv_data->rx;
- }
-
-@@ -304,11 +443,11 @@ static int u16_writer(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
-- || (drv_data->tx == drv_data->tx_end))
-+ if ((!(read_sssr(reg) & SSSR_TNF))
-+ || (drv_data->tx == drv_data->tx_end))
- return 0;
-
-- write_SSDR(*(u16 *)(drv_data->tx), reg);
-+ write_ssdr(*(u16 *)(drv_data->tx), reg);
- drv_data->tx += 2;
-
- return 1;
-@@ -318,9 +457,9 @@ static int u16_reader(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- while ((read_SSSR(reg) & SSSR_RNE)
-- && (drv_data->rx < drv_data->rx_end)) {
-- *(u16 *)(drv_data->rx) = read_SSDR(reg);
-+ while ((read_sssr(reg) & SSSR_RNE)
-+ && (drv_data->rx < drv_data->rx_end)) {
-+ *(u16 *)(drv_data->rx) = read_ssdr(reg);
- drv_data->rx += 2;
- }
-
-@@ -331,11 +470,11 @@ static int u32_writer(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
-- || (drv_data->tx == drv_data->tx_end))
-+ if ((!(read_sssr(reg) & SSSR_TNF))
-+ || (drv_data->tx == drv_data->tx_end))
- return 0;
-
-- write_SSDR(*(u32 *)(drv_data->tx), reg);
-+ write_ssdr(*(u32 *)(drv_data->tx), reg);
- drv_data->tx += 4;
-
- return 1;
-@@ -345,9 +484,9 @@ static int u32_reader(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- while ((read_SSSR(reg) & SSSR_RNE)
-- && (drv_data->rx < drv_data->rx_end)) {
-- *(u32 *)(drv_data->rx) = read_SSDR(reg);
-+ while ((read_sssr(reg) & SSSR_RNE)
-+ && (drv_data->rx < drv_data->rx_end)) {
-+ *(u32 *)(drv_data->rx) = read_ssdr(reg);
- drv_data->rx += 4;
- }
-
-@@ -443,20 +582,11 @@ static void unmap_dma_buffers(struct driver_data *drv_data)
- /* caller already set message->status; dma and pio irqs are blocked */
- static void giveback(struct driver_data *drv_data)
- {
-- struct spi_transfer* last_transfer;
-- unsigned long flags;
-- struct spi_message *msg;
-+ struct spi_transfer *last_transfer;
-
-- spin_lock_irqsave(&drv_data->lock, flags);
-- msg = drv_data->cur_msg;
-- drv_data->cur_msg = NULL;
-- drv_data->cur_transfer = NULL;
-- queue_work(drv_data->workqueue, &drv_data->pump_messages);
-- spin_unlock_irqrestore(&drv_data->lock, flags);
--
-- last_transfer = list_entry(msg->transfers.prev,
-- struct spi_transfer,
-- transfer_list);
-+ last_transfer = list_entry(drv_data->cur_msg->transfers.prev,
-+ struct spi_transfer,
-+ transfer_list);
-
- /* Delay if requested before any change in chip select */
- if (last_transfer->delay_usecs)
-@@ -475,41 +605,33 @@ static void giveback(struct driver_data *drv_data)
- * time with the following tests unless this was hinted.
- *
- * We cannot postpone this until pump_messages, because
-- * after calling msg->complete (below) the driver that
-- * sent the current message could be unloaded, which
-- * could invalidate the cs_control() callback...
-+ * after calling spi_finalize_current_message (below) the
-+ * driver that sent the current message could be unloaded,
-+ * which could invalidate the cs_control() callback...
- */
--
- /* get a pointer to the next message, if any */
-- spin_lock_irqsave(&drv_data->lock, flags);
-- if (list_empty(&drv_data->queue))
-- next_msg = NULL;
-- else
-- next_msg = list_entry(drv_data->queue.next,
-- struct spi_message, queue);
-- spin_unlock_irqrestore(&drv_data->lock, flags);
-+ next_msg = spi_get_next_queued_message(drv_data->master);
-
- /* see if the next and current messages point
- * to the same chip
- */
-- if (next_msg && next_msg->spi != msg->spi)
-+ if (next_msg && next_msg->spi != drv_data->cur_msg->spi)
- next_msg = NULL;
-- if (!next_msg || msg->state == ERROR_STATE)
-+ if (!next_msg || drv_data->cur_msg->state == ERROR_STATE)
- cs_deassert(drv_data);
- }
-
-- msg->state = NULL;
-- if (msg->complete)
-- msg->complete(msg->context);
--
-+ drv_data->cur_msg = NULL;
-+ drv_data->cur_transfer = NULL;
- drv_data->cur_chip = NULL;
-+ spi_finalize_current_message(drv_data->master);
- }
-
- static int wait_ssp_rx_stall(void const __iomem *ioaddr)
- {
- unsigned long limit = loops_per_jiffy << 1;
-
-- while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
-+ while ((read_sssr(ioaddr) & SSSR_BSY) && --limit)
- cpu_relax();
-
- return limit;
-@@ -532,12 +654,12 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
- /* Stop and reset */
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
-- write_SSSR_CS(drv_data, drv_data->clear_sr);
-- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-+ write_sssr_cs(drv_data, drv_data->clear_sr);
-+ write_sscr1(read_sscr1(reg) & ~drv_data->dma_cr1, reg);
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(0, reg);
-+ write_ssto(0, reg);
- flush(drv_data);
-- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-+ write_sscr0(read_sscr0(reg) & ~SSCR0_SSE, reg);
-
- unmap_dma_buffers(drv_data);
-
-@@ -553,8 +675,8 @@ static void dma_transfer_complete(struct driver_data *drv_data)
- struct spi_message *msg = drv_data->cur_msg;
-
- /* Clear and disable interrupts on SSP and DMA channels*/
-- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
-- write_SSSR_CS(drv_data, drv_data->clear_sr);
-+ write_sscr1(read_sscr1(reg) & ~drv_data->dma_cr1, reg);
-+ write_sssr_cs(drv_data, drv_data->clear_sr);
- DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
- DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
-
-@@ -630,7 +752,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
- u32 irq_status;
- void __iomem *reg = drv_data->ioaddr;
-
-- irq_status = read_SSSR(reg) & drv_data->mask_sr;
-+ irq_status = read_sssr(reg) & drv_data->mask_sr;
- if (irq_status & SSSR_ROR) {
- dma_error_stop(drv_data, "dma_transfer: fifo overrun");
- return IRQ_HANDLED;
-@@ -639,7 +761,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
- /* Check for false positive timeout */
- if ((irq_status & SSSR_TINT)
- && (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
-- write_SSSR(SSSR_TINT, reg);
-+ write_sssr(SSSR_TINT, reg);
- return IRQ_HANDLED;
- }
-
-@@ -648,7 +770,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
- /* Clear and disable timeout interrupt, do the rest in
- * dma_transfer_complete */
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(0, reg);
-+ write_ssto(0, reg);
-
- /* finish this transfer, start the next */
- dma_transfer_complete(drv_data);
-@@ -666,23 +788,26 @@ static void reset_sccr1(struct driver_data *drv_data)
- struct chip_data *chip = drv_data->cur_chip;
- u32 sccr1_reg;
-
-- sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
-- sccr1_reg &= ~SSCR1_RFT;
-+ sccr1_reg = read_sscr1(reg) & ~drv_data->int_cr1;
-+ if (drv_data->ssp_type == CE5X00_SSP)
-+ sccr1_reg &= ~CE5X00_SSCR1_RFT;
-+ else
-+ sccr1_reg &= ~SSCR1_RFT;
- sccr1_reg |= chip->threshold;
-- write_SSCR1(sccr1_reg, reg);
-+ write_sscr1(sccr1_reg, reg);
- }
-
--static void int_error_stop(struct driver_data *drv_data, const char* msg)
-+static void int_error_stop(struct driver_data *drv_data, const char *msg)
- {
- void __iomem *reg = drv_data->ioaddr;
-
- /* Stop and reset SSP */
-- write_SSSR_CS(drv_data, drv_data->clear_sr);
-+ write_sssr_cs(drv_data, drv_data->clear_sr);
- reset_sccr1(drv_data);
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(0, reg);
-+ write_ssto(0, reg);
- flush(drv_data);
-- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-+ write_sscr0(read_sscr0(reg) & ~SSCR0_SSE, reg);
-
- dev_err(&drv_data->pdev->dev, "%s\n", msg);
-
-@@ -695,10 +820,10 @@ static void int_transfer_complete(struct driver_data *drv_data)
- void __iomem *reg = drv_data->ioaddr;
-
- /* Stop SSP */
-- write_SSSR_CS(drv_data, drv_data->clear_sr);
-+ write_sssr_cs(drv_data, drv_data->clear_sr);
- reset_sccr1(drv_data);
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(0, reg);
-+ write_ssto(0, reg);
-
- /* Update total byte transferred return count actual bytes read */
- drv_data->cur_msg->actual_length += drv_data->len -
-@@ -715,14 +840,16 @@ static void int_transfer_complete(struct driver_data *drv_data)
- tasklet_schedule(&drv_data->pump_transfers);
- }
-
-+#ifndef CONFIG_GEN3_SPI
-+
- static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
- {
- void __iomem *reg = drv_data->ioaddr;
-
-- u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
-+ u32 irq_mask = (read_sscr1(reg) & SSCR1_TIE) ?
- drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
-
-- u32 irq_status = read_SSSR(reg) & irq_mask;
-+ u32 irq_status = read_sssr(reg) & irq_mask;
-
- if (irq_status & SSSR_ROR) {
- int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
-@@ -730,7 +857,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
- }
-
- if (irq_status & SSSR_TINT) {
-- write_SSSR(SSSR_TINT, reg);
-+ write_sssr_cs(drv_data, SSSR_TINT);
- if (drv_data->read(drv_data)) {
- int_transfer_complete(drv_data);
- return IRQ_HANDLED;
-@@ -751,10 +878,12 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
- }
-
- if (drv_data->tx == drv_data->tx_end) {
-- u32 bytes_left;
-+#ifndef CONFIG_GEN3_SPI
-+ u32 bytes_left = 0;
-+#endif
- u32 sccr1_reg;
-
-- sccr1_reg = read_SSCR1(reg);
-+ sccr1_reg = read_sscr1(reg);
- sccr1_reg &= ~SSCR1_TIE;
-
- /*
-@@ -762,13 +891,13 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
- * remaining RX bytes.
- */
- if (pxa25x_ssp_comp(drv_data)) {
--
-+#ifndef CONFIG_GEN3_SPI
- sccr1_reg &= ~SSCR1_RFT;
-
- bytes_left = drv_data->rx_end - drv_data->rx;
- switch (drv_data->n_bytes) {
- case 4:
-- bytes_left >>= 1;
-+ bytes_left >>= 2;
- case 2:
- bytes_left >>= 1;
- }
-@@ -777,23 +906,198 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
- bytes_left = RX_THRESH_DFLT;
-
- sccr1_reg |= SSCR1_RxTresh(bytes_left);
-+#endif
-+ }
-+ write_sscr1(sccr1_reg, reg);
-+#ifdef CONFIG_GEN3_SPI
-+ if (!wait_ssp_rx_stall(reg)) {
-+ int_error_stop(drv_data,
-+ "interrupt_transfer: rx stall failed");
-+ return IRQ_HANDLED;
-+ }
-+
-+ if (!drv_data->read(drv_data)) {
-+ int_error_stop(drv_data,
-+ "interrupt_transfer: "
-+ "trailing byte read failed");
-+ return IRQ_HANDLED;
-+ }
-+
-+ int_transfer_complete(drv_data);
-+#endif
-+
-+ }
-+
-+ /* We did something */
-+ return IRQ_HANDLED;
-+}
-+#else
-+#ifdef WANT_TO_USE_THIS
-+static int is_txfifo_empty(struct driver_data *drv_data, u32 tfl_mask)
-+{
-+ void __iomem *reg = drv_data->ioaddr;
-+ u32 sssr = read_sssr(reg);
-+ u32 tx_fifo_entry = 0;
-+ tx_fifo_entry = (sssr & tfl_mask)>>8;
-+ if ((sssr & SSSR_TNF) && (!tx_fifo_entry))
-+ return 1;
-+ return 0;
-+}
-+#endif
-+
-+static void pxa2xx_update_tx_threshold(struct driver_data *drv_data,
-+ u32 threshold)
-+{
-+ void __iomem *reg = drv_data->ioaddr;
-+ u32 sscr1_reg = 0;
-+ sscr1_reg = read_sscr1(reg);
-+ sscr1_reg |= SSCR1_TIE;
-+ if (drv_data->ssp_type == CE5X00_SSP) {
-+ sscr1_reg &= ~CE5X00_SSCR1_TFT;
-+ sscr1_reg |= CE5X00_SSCR1_TxTresh(threshold);
-+ } else {
-+ sscr1_reg &= ~SSCR1_TFT;
-+ sscr1_reg |= SSCR1_TxTresh(threshold);
-+ }
-+
-+ write_sscr1(sscr1_reg, reg);
-+}
-+
-+static void pxa2xx_mask_intr(void __iomem *reg, u32 intr)
-+{
-+ u32 mask;
-+ mask = read_sscr1(reg) & ~intr;
-+ write_sscr1(mask, reg);
-+}
-+
-+static void pxa2xx_unmask_intr(void __iomem *reg, u32 intr)
-+{
-+ u32 mask;
-+ mask = read_sscr1(reg) | intr;
-+ write_sscr1(mask, reg);
-+}
-+
-+static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
-+{
-+ void __iomem *reg = drv_data->ioaddr;
-+
-+ u32 tx_count;
-+ u32 irq_mask = (read_sscr1(reg) & SSCR1_TIE) ?
-+ drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
-+
-+ int left;
-+
-+ u32 tmp_sssr = read_sssr(reg);
-+ u32 irq_status = tmp_sssr & irq_mask;
-+ /*
-+ * Transmit FIFO Level Depth/MASK/Default value
-+ */
-+ u32 fifo_depth, sssr_tfl_mask, sscr1_tft_mask, tfl_default;
-+
-+ /*
-+ * Check whether the irq is valid spi interrupt
-+ */
-+ if (!(tmp_sssr & (SSSR_TFS | SSSR_RFS | SSSR_ROR)))
-+ return IRQ_NONE;
-+
-+ switch (drv_data->ssp_type) {
-+ case CE4100_SSP:
-+ fifo_depth = CE4X00_FIFO_DEPTH;
-+ sssr_tfl_mask = SSSR_TFL_MASK;
-+ sscr1_tft_mask = SSCR1_TFT;
-+ tfl_default = TX_THRESH_DFLT;
-+ break;
-+ case CE5X00_SSP:
-+ fifo_depth = CE5X00_FIFO_DEPTH;
-+ sssr_tfl_mask = CE5X00_SSSR_TFL_MASK;
-+ sscr1_tft_mask = CE5X00_SSCR1_TFT;
-+ tfl_default = TX_THRESH_CE5X00_DFLT;
-+ break;
-+ default:
-+ int_error_stop(drv_data, "Unsupported spi contoller type");
-+ return IRQ_HANDLED;
-+ }
-+
-+
-+ if (irq_status & SSSR_ROR) {
-+ int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
-+ return IRQ_HANDLED;
-+ }
-+
-+
-+ if (irq_status & SSSR_TINT) {
-+ write_sssr_cs(drv_data, SSSR_TINT);
-+ if (drv_data->read(drv_data)) {
-+ int_transfer_complete(drv_data);
-+ return IRQ_HANDLED;
- }
-- write_SSCR1(sccr1_reg, reg);
- }
-
-+
-+ if (irq_status & SSSR_TFS) {
-+
-+ /*
-+ * Mask the Transmit interrupt
-+ */
-+ pxa2xx_mask_intr(reg, SSCR1_TIE);
-+
-+ left = (drv_data->tx_end - drv_data->tx) / drv_data->n_bytes;
-+
-+ tmp_sssr = read_sssr(reg);
-+ tmp_sssr = (tmp_sssr & sssr_tfl_mask)>>8;
-+ /*
-+ * Choose the correct tx_count to fill the Tx fifo and
-+ * avoid the Rx Fifo overrun
-+ */
-+ tx_count = (fifo_depth - 1) - tmp_sssr;
-+
-+ if (left <= tx_count) {
-+ if (left > 0) {
-+ drv_data->read(drv_data);
-+ pxa2xx_update_tx_threshold(drv_data, 1);
-+ while ((left) > 0) {
-+ left--;
-+ drv_data->write(drv_data);
-+ }
-+ pxa2xx_unmask_intr(reg, SSCR1_TIE);
-+ return IRQ_HANDLED;
-+ } else {
-+ /*
-+ * Tx transfer is done now,
-+ * Read data when controller is not busy.
-+ */
-+ wait_till_not_busy(drv_data);
-+ drv_data->read(drv_data);
-+ pxa2xx_unmask_intr(reg, SSCR1_TIE);
-+ int_transfer_complete(drv_data);
-+ return IRQ_HANDLED;
-+ }
-+ } else {
-+ left = (left > tx_count) ? tx_count : left;
-+ drv_data->read(drv_data);
-+ while ((left) > 0) {
-+ left--;
-+ drv_data->write(drv_data);
-+ }
-+ pxa2xx_unmask_intr(reg, SSCR1_TIE);
-+ return IRQ_HANDLED;
-+ }
-+ }
- /* We did something */
- return IRQ_HANDLED;
- }
-+#endif
-
- static irqreturn_t ssp_int(int irq, void *dev_id)
- {
- struct driver_data *drv_data = dev_id;
- void __iomem *reg = drv_data->ioaddr;
-- u32 sccr1_reg = read_SSCR1(reg);
-+ u32 sccr1_reg = read_sscr1(reg);
- u32 mask = drv_data->mask_sr;
- u32 status;
-+ irqreturn_t ret;
-
-- status = read_SSSR(reg);
-+ status = read_sssr(reg);
-
- /* Ignore possible writes if we don't need to write */
- if (!(sccr1_reg & SSCR1_TIE))
-@@ -802,22 +1106,27 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
- if (!(status & mask))
- return IRQ_NONE;
-
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ mask_pvm(drv_data->ssp->pcidev);
-+#endif
- if (!drv_data->cur_msg) {
-
-- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
-- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
-+ write_sscr0(read_sscr0(reg) & ~SSCR0_SSE, reg);
-+ write_sscr1(read_sscr1(reg) & ~drv_data->int_cr1, reg);
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(0, reg);
-- write_SSSR_CS(drv_data, drv_data->clear_sr);
--
-- dev_err(&drv_data->pdev->dev, "bad message state "
-- "in interrupt handler\n");
-+ write_ssto(0, reg);
-+ write_sssr_cs(drv_data, drv_data->clear_sr);
-
-+ dev_err(&drv_data->pdev->dev,
-+ "bad message state in interrupt handler\n");
- /* Never fail */
- return IRQ_HANDLED;
- }
--
-- return drv_data->transfer_handler(drv_data);
-+ ret = drv_data->transfer_handler(drv_data);
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ unmask_pvm(drv_data->ssp->pcidev);
-+#endif
-+ return ret;
- }
-
- static int set_dma_burst_and_threshold(struct chip_data *chip,
-@@ -916,16 +1225,192 @@ static int set_dma_burst_and_threshold(struct chip_data *chip,
-
- return retval;
- }
-+#ifdef CONFIG_GEN3_SPI
-+/* this returns the value of DDS_FREQ not Input_Clock
-+ DDS_FREQ = Input_Clock ( DDS_CLK_RATEdec / 2^24) */
-+static unsigned long spi_clk_get_rate(int ssp_type)
-+{
-+ switch (ssp_type) {
-+ case CE5X00_SSP:
-+ /* CE5X00 clk is 10MHZ */
-+ return 10000000;
-+ case CE4100_SSP:
-+ /* CE4X00 clk is 3.684MHZ */
-+ default:
-+ return 3686400;
-+ }
-
-+ return 3686400;
-+}
-+#endif
-+
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+/* see Clanton SPI data sheet for implementation rationale */
-+u32 cln_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div)
-+{
-+ if (rate <= BITRATE_MAX && rate >= BITRATE_MIN) {
-+ if (rate >= BITRATE_50MHZ) {
-+ *dds = DDS_MAX;
-+ *clk_div = 0;
-+ return BITRATE_50MHZ;
-+ } else if (rate >= BITRATE_40MHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 0;
-+ return BITRATE_40MHZ;
-+ } else if (rate >= BITRATE_25MHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 0;
-+ return BITRATE_25MHZ;
-+ } else if (rate >= BITRATE_20MHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 1;
-+ return BITRATE_20MHZ;
-+ } else if (rate >= BITRATE_16667KHZ) {
-+ *dds = DDS_MAX;
-+ *clk_div = 2;
-+ return BITRATE_16667KHZ;
-+ } else if (rate >= BITRATE_13333KHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 2;
-+ return BITRATE_13333KHZ;
-+ } else if (rate >= BITRATE_12500KHZ) {
-+ *dds = DDS_200000;
-+ *clk_div = 0;
-+ return BITRATE_12500KHZ;
-+ } else if (rate >= BITRATE_10MHZ) {
-+ *dds = DDS_MAX;
-+ *clk_div = 4;
-+ return BITRATE_10MHZ;
-+ } else if (rate >= BITRATE_8MHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 4;
-+ return BITRATE_8MHZ;
-+ } else if (rate >= BITRATE_6250KHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 3;
-+ return BITRATE_6250KHZ;
-+ } else if (rate >= BITRATE_5MHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 4;
-+ return BITRATE_5MHZ;
-+ } else if (rate >= BITRATE_4MHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 9;
-+ return BITRATE_4MHZ;
-+ } else if (rate >= BITRATE_3125KHZ) {
-+ *dds = DDS_80000;
-+ *clk_div = 0;
-+ return BITRATE_3125KHZ;
-+ } else if (rate >= BITRATE_2500KHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 9;
-+ return BITRATE_2500KHZ;
-+ } else if (rate >= BITRATE_2MHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 19;
-+ return BITRATE_2MHZ;
-+ } else if (rate >= BITRATE_1563KHZ) {
-+ *dds = DDS_40000;
-+ *clk_div = 0;
-+ return BITRATE_1563KHZ;
-+ } else if (rate >= BITRATE_1250KHZ) {
-+ *dds = DDS_200000;
-+ *clk_div = 9;
-+ return BITRATE_1250KHZ;
-+ } else if (rate >= BITRATE_1MHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 24;
-+ return BITRATE_1MHZ;
-+ } else if (rate >= BITRATE_800KHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 49;
-+ return BITRATE_800KHZ;
-+ } else if (rate >= BITRATE_781KHZ) {
-+ *dds = DDS_20000;
-+ *clk_div = 0;
-+ return BITRATE_781KHZ;
-+ } else if (rate >= BITRATE_625KHZ) {
-+ *dds = DDS_200000;
-+ *clk_div = 19;
-+ return BITRATE_625KHZ;
-+ } else if (rate >= BITRATE_500KHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 49;
-+ return BITRATE_500KHZ;
-+ } else if (rate >= BITRATE_400KHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 99;
-+ return BITRATE_400KHZ;
-+ } else if (rate >= BITRATE_390KHZ) {
-+ *dds = DDS_10000;
-+ *clk_div = 0;
-+ return BITRATE_390KHZ;
-+ } else if (rate >= BITRATE_250KHZ) {
-+ *dds = DDS_400000;
-+ *clk_div = 99;
-+ return BITRATE_250KHZ;
-+ } else if (rate >= BITRATE_200KHZ) {
-+ *dds = DDS_666666;
-+ *clk_div = 199;
-+ return BITRATE_200KHZ;
-+ } else if (rate >= BITRATE_195KHZ) {
-+ *dds = DDS_8000;
-+ *clk_div = 0;
-+ return BITRATE_195KHZ;
-+ } else if (rate >= BITRATE_125KHZ) {
-+ *dds = DDS_100000;
-+ *clk_div = 49;
-+ return BITRATE_125KHZ;
-+ } else if (rate >= BITRATE_100KHZ) {
-+ *dds = DDS_200000;
-+ *clk_div = 124;
-+ return BITRATE_100KHZ;
-+ } else if (rate >= BITRATE_50KHZ) {
-+ *dds = DDS_100000;
-+ *clk_div = 124;
-+ return BITRATE_50KHZ;
-+ } else if (rate >= BITRATE_25KHZ) {
-+ *dds = DDS_80000;
-+ *clk_div = 124;
-+ return BITRATE_25KHZ;
-+ } else if (rate >= BITRATE_10KHZ) {
-+ *dds = DDS_20000;
-+ *clk_div = 77;
-+ return BITRATE_10KHZ;
-+ } else if (rate >= BITRATE_5KHZ) {
-+ *dds = DDS_20000;
-+ *clk_div = 154;
-+ return BITRATE_5KHZ;
-+ } else if (rate >= BITRATE_1KHZ) {
-+ *dds = DDS_8000;
-+ *clk_div = 194;
-+ return BITRATE_1KHZ;
-+ }
-+ } else {
-+ *dds = DDS_8000;
-+ *clk_div = 194;
-+ return BITRATE_MIN;
-+ }
-+ return 0;
-+}
-+#else
-+/* this returns the value that SCR needs to be set to
-+ Bit rate = DDS_FREQ / (2 x (SCR + 1)) */
- static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
- {
-+#ifdef CONFIG_GEN3_SPI
-+ unsigned long ssp_clk = spi_clk_get_rate(ssp->type);
-+#else
- unsigned long ssp_clk = clk_get_rate(ssp->clk);
-+#endif
-
-- if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
-+ if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP
-+ || ssp->type == CE5X00_SSP)
- return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
- else
- return ((ssp_clk / rate - 1) & 0xfff) << 8;
- }
-+#endif /* CONFIG_INTEL_QUARK_X1000_SOC */
-
- static void pump_transfers(unsigned long data)
- {
-@@ -934,7 +1419,11 @@ static void pump_transfers(unsigned long data)
- struct spi_transfer *transfer = NULL;
- struct spi_transfer *previous = NULL;
- struct chip_data *chip = NULL;
-+#ifndef CONFIG_INTEL_QUARK_X1000_SOC
- struct ssp_device *ssp = drv_data->ssp;
-+#else
-+ u32 actual_speed = 0;
-+#endif
- void __iomem *reg = drv_data->ioaddr;
- u32 clk_div = 0;
- u8 bits = 0;
-@@ -947,8 +1436,11 @@ static void pump_transfers(unsigned long data)
- /* Get current state information */
- message = drv_data->cur_msg;
- transfer = drv_data->cur_transfer;
-+
- chip = drv_data->cur_chip;
-
-+ if (transfer->bits_per_word)
-+ chip->n_bytes = (transfer->bits_per_word + 7)/8;
- /* Handle for abort */
- if (message->state == ERROR_STATE) {
- message->status = -EIO;
-@@ -992,11 +1484,11 @@ static void pump_transfers(unsigned long data)
- }
-
- /* warn ... we force this to PIO mode */
-- if (printk_ratelimit())
-- dev_warn(&message->spi->dev, "pump_transfers: "
-- "DMA disabled for transfer length %ld "
-- "greater than %d\n",
-- (long)drv_data->len, MAX_DMA_LEN);
-+ dev_warn_ratelimited(&message->spi->dev,
-+ "pump_transfers: "
-+ "DMA disabled for transfer length %ld "
-+ "greater than %d\n",
-+ (long)drv_data->len, MAX_DMA_LEN);
- }
-
- /* Setup the transfer state based on the type of transfer */
-@@ -1009,19 +1501,21 @@ static void pump_transfers(unsigned long data)
- drv_data->n_bytes = chip->n_bytes;
- drv_data->dma_width = chip->dma_width;
- drv_data->tx = (void *)transfer->tx_buf;
-- drv_data->tx_end = drv_data->tx + transfer->len;
-+ drv_data->tx_end = drv_data->tx
-+ + (transfer->len/drv_data->n_bytes)*drv_data->n_bytes;
- drv_data->rx = transfer->rx_buf;
-- drv_data->rx_end = drv_data->rx + transfer->len;
-+ drv_data->rx_end = drv_data->rx
-+ + (transfer->len/drv_data->n_bytes)*drv_data->n_bytes;
- drv_data->rx_dma = transfer->rx_dma;
- drv_data->tx_dma = transfer->tx_dma;
-- drv_data->len = transfer->len & DCMD_LENGTH;
-+ drv_data->len = (transfer->len/drv_data->n_bytes)
-+ * drv_data->n_bytes & DCMD_LENGTH;
- drv_data->write = drv_data->tx ? chip->write : null_writer;
- drv_data->read = drv_data->rx ? chip->read : null_reader;
-
- /* Change speed and bit per word on a per transfer */
- cr0 = chip->cr0;
- if (transfer->speed_hz || transfer->bits_per_word) {
--
- bits = chip->bits_per_word;
- speed = chip->speed_hz;
-
-@@ -1031,8 +1525,13 @@ static void pump_transfers(unsigned long data)
- if (transfer->bits_per_word)
- bits = transfer->bits_per_word;
-
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ actual_speed = cln_set_clk_regvals
-+ (speed, &chip->dds_rate, &clk_div);
-+ clk_div = (clk_div << 8);
-+#else
- clk_div = ssp_get_clk_div(ssp, speed);
--
-+#endif
- if (bits <= 8) {
- drv_data->n_bytes = 1;
- drv_data->dma_width = DCMD_WIDTH1;
-@@ -1061,18 +1560,32 @@ static void pump_transfers(unsigned long data)
- if (set_dma_burst_and_threshold(chip, message->spi,
- bits, &dma_burst,
- &dma_thresh))
-- if (printk_ratelimit())
-- dev_warn(&message->spi->dev,
-- "pump_transfers: "
-- "DMA burst size reduced to "
-- "match bits_per_word\n");
-+ dev_warn_ratelimited(&message->spi->dev,
-+ "pump_transfers: "
-+ "DMA burst size reduced to"
-+ " match bits_per_word\n");
- }
-
-- cr0 = clk_div
-- | SSCR0_Motorola
-- | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
-- | SSCR0_SSE
-- | (bits > 16 ? SSCR0_EDSS : 0);
-+ switch (drv_data->ssp_type) {
-+ case CE5X00_SSP:
-+ chip->cr0 = clk_div
-+ | CE5X00_SSCR0_Motorola
-+ | CE5X00_SSCR0_DataSize(bits > 32 ?
-+ 8 : bits)
-+ | SSCR0_SSE;
-+ break;
-+ case CE4100_SSP:
-+ case PXA25x_SSP:
-+ default:
-+ chip->cr0 = clk_div
-+ | SSCR0_Motorola
-+ | SSCR0_DataSize(bits > 16 ?
-+ bits - 16 : bits)
-+ | SSCR0_SSE
-+ | (bits > 16 ? SSCR0_EDSS : 0);
-+ }
-+
-+ cr0 = chip->cr0;
- }
-
- message->state = RUNNING_STATE;
-@@ -1138,7 +1651,7 @@ static void pump_transfers(unsigned long data)
-
- /* Clear status and start DMA engine */
- cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
-- write_SSSR(drv_data->clear_sr, reg);
-+ write_sssr(drv_data->clear_sr, reg);
- DCSR(drv_data->rx_channel) |= DCSR_RUN;
- DCSR(drv_data->tx_channel) |= DCSR_RUN;
- } else {
-@@ -1147,100 +1660,72 @@ static void pump_transfers(unsigned long data)
-
- /* Clear status */
- cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
-- write_SSSR_CS(drv_data, drv_data->clear_sr);
-+ write_sssr_cs(drv_data, drv_data->clear_sr);
- }
-
- /* see if we need to reload the config registers */
-- if ((read_SSCR0(reg) != cr0)
-- || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
-- (cr1 & SSCR1_CHANGE_MASK)) {
-+ if (drv_data->ssp_type == CE5X00_SSP) {
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ if (read_dds_rate(reg) != chip->dds_rate)
-+ write_dds_rate(chip->dds_rate, reg);
-+#endif
-+ if ((read_sscr0(reg) != cr0)
-+ || (read_sscr1(reg) & CE5X00_SSCR1_CHANGE_MASK) !=
-+ (cr1 & CE5X00_SSCR1_CHANGE_MASK)) {
-+ /* stop the SSP, and update the other bits */
-+ write_sscr0(cr0 & ~SSCR0_SSE, reg);
-+ if (!pxa25x_ssp_comp(drv_data))
-+ write_ssto(chip->timeout, reg);
-+ /* first set CR1 w/o interrupt and service enables */
-+ write_sscr1(cr1 & CE5X00_SSCR1_CHANGE_MASK, reg);
-+ /* restart the SSP */
-+ write_sscr0(cr0, reg);
-
-+ } else {
-+ if (!pxa25x_ssp_comp(drv_data))
-+ write_ssto(chip->timeout, reg);
-+ }
-+ } else if ((read_sscr0(reg) != cr0)
-+ || (read_sscr1(reg) & SSCR1_CHANGE_MASK) !=
-+ (cr1 & SSCR1_CHANGE_MASK)) {
- /* stop the SSP, and update the other bits */
-- write_SSCR0(cr0 & ~SSCR0_SSE, reg);
-+ write_sscr0(cr0 & ~SSCR0_SSE, reg);
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(chip->timeout, reg);
-+ write_ssto(chip->timeout, reg);
- /* first set CR1 without interrupt and service enables */
-- write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
-+ write_sscr1(cr1 & SSCR1_CHANGE_MASK, reg);
- /* restart the SSP */
-- write_SSCR0(cr0, reg);
-+ write_sscr0(cr0, reg);
-
-- } else {
-- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(chip->timeout, reg);
-+ } else if (!pxa25x_ssp_comp(drv_data)) {
-+ write_ssto(chip->timeout, reg);
- }
--
- cs_assert(drv_data);
-
- /* after chip select, release the data by enabling service
- * requests and interrupts, without changing any mode bits */
-- write_SSCR1(cr1, reg);
-+ write_sscr1(cr1, reg);
- }
-
--static void pump_messages(struct work_struct *work)
-+static int transfer_one_message(struct spi_master *master,
-+ struct spi_message *msg)
- {
-- struct driver_data *drv_data =
-- container_of(work, struct driver_data, pump_messages);
-- unsigned long flags;
--
-- /* Lock queue and check for queue work */
-- spin_lock_irqsave(&drv_data->lock, flags);
-- if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
-- drv_data->busy = 0;
-- spin_unlock_irqrestore(&drv_data->lock, flags);
-- return;
-- }
-+ struct driver_data *drv_data = spi_master_get_devdata(master);
-
-- /* Make sure we are not already running a message */
-- if (drv_data->cur_msg) {
-- spin_unlock_irqrestore(&drv_data->lock, flags);
-- return;
-- }
--
-- /* Extract head of queue */
-- drv_data->cur_msg = list_entry(drv_data->queue.next,
-- struct spi_message, queue);
-- list_del_init(&drv_data->cur_msg->queue);
-+ /* Initial message state */
-+ drv_data->cur_msg = msg;
-+ msg->state = START_STATE;
-
-- /* Initial message state*/
-- drv_data->cur_msg->state = START_STATE;
-- drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
-- struct spi_transfer,
-- transfer_list);
-+ drv_data->cur_transfer = list_entry(msg->transfers.next,
-+ struct spi_transfer, transfer_list);
-
- /* prepare to setup the SSP, in pump_transfers, using the per
- * chip configuration */
-- drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
-+ drv_data->cur_chip = spi_get_ctldata(msg->spi);
-
-- /* Mark as busy and launch transfers */
-+ /* Launch transfers */
- tasklet_schedule(&drv_data->pump_transfers);
-
-- drv_data->busy = 1;
-- spin_unlock_irqrestore(&drv_data->lock, flags);
--}
--
--static int transfer(struct spi_device *spi, struct spi_message *msg)
--{
-- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
-- unsigned long flags;
--
-- spin_lock_irqsave(&drv_data->lock, flags);
--
-- if (drv_data->run == QUEUE_STOPPED) {
-- spin_unlock_irqrestore(&drv_data->lock, flags);
-- return -ESHUTDOWN;
-- }
--
-- msg->actual_length = 0;
-- msg->status = -EINPROGRESS;
-- msg->state = START_STATE;
--
-- list_add_tail(&msg->queue, &drv_data->queue);
--
-- if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
-- queue_work(drv_data->workqueue, &drv_data->pump_messages);
--
-- spin_unlock_irqrestore(&drv_data->lock, flags);
--
- return 0;
- }
-
-@@ -1267,8 +1752,9 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
- if (gpio_is_valid(chip_info->gpio_cs)) {
- err = gpio_request(chip_info->gpio_cs, "SPI_CS");
- if (err) {
-- dev_err(&spi->dev, "failed to request chip select "
-- "GPIO%d\n", chip_info->gpio_cs);
-+ dev_err(&spi->dev,
-+ "failed to request chip select "
-+ "GPIO%d\n", chip_info->gpio_cs);
- return err;
- }
-
-@@ -1282,6 +1768,31 @@ static int setup_cs(struct spi_device *spi, struct chip_data *chip,
- return err;
- }
-
-+static int prepare_transfer_hardware(struct spi_master *master)
-+{
-+ struct driver_data *drv_data = spi_master_get_devdata(master);
-+
-+ /*
-+ * Just make sure we have all we need to run the transfer by syncing
-+ * with the runtime PM framework.
-+ */
-+ pm_runtime_get_sync(&drv_data->pdev->dev);
-+ return 0;
-+}
-+
-+static int unprepare_transfer_hardware(struct spi_master *master)
-+{
-+ struct driver_data *drv_data = spi_master_get_devdata(master);
-+
-+ /* nothing more to do - disable spi/ssp and power off */
-+ write_sscr0(0, drv_data->ioaddr);
-+ clk_disable(drv_data->ssp->clk);
-+
-+ pm_runtime_put(&drv_data->pdev->dev);
-+
-+ return 0;
-+}
-+
- static int setup(struct spi_device *spi)
- {
- struct pxa2xx_spi_chip *chip_info = NULL;
-@@ -1289,21 +1800,29 @@ static int setup(struct spi_device *spi)
- struct driver_data *drv_data = spi_master_get_devdata(spi->master);
- struct ssp_device *ssp = drv_data->ssp;
- unsigned int clk_div;
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ u32 actual_speed;
-+#endif
- uint tx_thres = TX_THRESH_DFLT;
- uint rx_thres = RX_THRESH_DFLT;
--
-- if (!pxa25x_ssp_comp(drv_data)
-+ if (drv_data->ssp_type == CE5X00_SSP) {
-+ tx_thres = TX_THRESH_CE5X00_DFLT;
-+ rx_thres = RX_THRESH_CE5X00_DFLT;
-+ }
-+ if ((!pxa25x_ssp_comp(drv_data) || pxa25x_ssp_comp(drv_data) == 2)
- && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
-- dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
-- "b/w not 4-32 for type non-PXA25x_SSP\n",
-- drv_data->ssp_type, spi->bits_per_word);
-+ dev_err(&spi->dev,
-+ "failed setup: ssp_type=%d, bits/wrd=%d "
-+ "b/w not 4-32 for type non-PXA25x_SSP\n",
-+ drv_data->ssp_type, spi->bits_per_word);
- return -EINVAL;
-- } else if (pxa25x_ssp_comp(drv_data)
-+ } else if (pxa25x_ssp_comp(drv_data) == 1
- && (spi->bits_per_word < 4
- || spi->bits_per_word > 16)) {
-- dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
-- "b/w not 4-16 for type PXA25x_SSP\n",
-- drv_data->ssp_type, spi->bits_per_word);
-+ dev_err(&spi->dev,
-+ "failed setup: ssp_type=%d, bits/wrd=%d "
-+ "b/w not 4-16 for type PXA25x_SSP\n",
-+ drv_data->ssp_type, spi->bits_per_word);
- return -EINVAL;
- }
-
-@@ -1319,8 +1838,9 @@ static int setup(struct spi_device *spi)
-
- if (drv_data->ssp_type == CE4100_SSP) {
- if (spi->chip_select > 4) {
-- dev_err(&spi->dev, "failed setup: "
-- "cs number must not be > 4.\n");
-+ dev_err(&spi->dev,
-+ "failed setup: "
-+ "cs number must not be > 4.\n");
- kfree(chip);
- return -EINVAL;
- }
-@@ -1328,6 +1848,7 @@ static int setup(struct spi_device *spi)
- chip->frm = spi->chip_select;
- } else
- chip->gpio_cs = -1;
-+
- chip->enable_dma = 0;
- chip->timeout = TIMOUT_DFLT;
- chip->dma_burst_size = drv_data->master_info->enable_dma ?
-@@ -1340,6 +1861,7 @@ static int setup(struct spi_device *spi)
-
- /* chip_info isn't always needed */
- chip->cr1 = 0;
-+ chip->cr0 = 0;
- if (chip_info) {
- if (chip_info->timeout)
- chip->timeout = chip_info->timeout;
-@@ -1353,9 +1875,6 @@ static int setup(struct spi_device *spi)
- chip->cr1 = SSCR1_LBM;
- }
-
-- chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
-- (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
--
- /* set dma burst and threshold outside of chip_info path so that if
- * chip_info goes away after setting chip->enable_dma, the
- * burst and threshold can still respond to changes in bits_per_word */
-@@ -1364,33 +1883,73 @@ static int setup(struct spi_device *spi)
- if (set_dma_burst_and_threshold(chip, spi, spi->bits_per_word,
- &chip->dma_burst_size,
- &chip->dma_threshold)) {
-- dev_warn(&spi->dev, "in setup: DMA burst size reduced "
-- "to match bits_per_word\n");
-+ dev_warn(&spi->dev,
-+ "in setup: DMA burst size reduced "
-+ "to match bits_per_word\n");
- }
- }
--
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ actual_speed = cln_set_clk_regvals(spi->max_speed_hz,
-+ &chip->dds_rate, &clk_div);
-+ clk_div = (clk_div << 8);
-+#else
- clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz);
-+#endif
- chip->speed_hz = spi->max_speed_hz;
-
-- chip->cr0 = clk_div
-+ switch (drv_data->ssp_type) {
-+ case CE5X00_SSP:
-+ chip->cr0 = clk_div
-+ | CE5X00_SSCR0_Motorola
-+ | CE5X00_SSCR0_DataSize(spi->bits_per_word > 32 ?
-+ 8 : spi->bits_per_word)
-+ | SSCR0_SSE;
-+ chip->threshold = (CE5X00_SSCR1_RxTresh(rx_thres)
-+ & CE5X00_SSCR1_RFT) |
-+ (CE5X00_SSCR1_TxTresh(tx_thres) & CE5X00_SSCR1_TFT);
-+ break;
-+ case CE4100_SSP:
-+ case PXA25x_SSP:
-+ default:
-+ chip->cr0 = clk_div
- | SSCR0_Motorola
- | SSCR0_DataSize(spi->bits_per_word > 16 ?
- spi->bits_per_word - 16 : spi->bits_per_word)
- | SSCR0_SSE
- | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
-+ chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
-+ (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
-+ }
-+
- chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
-+ | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0)
-+ | (((spi->mode & SPI_LOOP) != 0) ? SSCR1_LBM : 0);
-+#else
- chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
- | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
-+#endif
-
- /* NOTE: PXA25x_SSP _could_ use external clocking ... */
- if (!pxa25x_ssp_comp(drv_data))
-- dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
-+ dev_dbg(&spi->dev,
-+ "%ld Hz actual, %s\n",
-+#ifndef CONFIG_GEN3_SPI
- clk_get_rate(ssp->clk)
-+#else
-+ spi_clk_get_rate(ssp->type)
-+#endif
- / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
- chip->enable_dma ? "DMA" : "PIO");
- else
-- dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
-+ dev_dbg(&spi->dev,
-+ "%ld Hz actual, %s\n",
-+#ifndef CONFIG_GEN3_SPI
- clk_get_rate(ssp->clk) / 2
-+#else
-+ spi_clk_get_rate(ssp->type) / 2
-+#endif
- / (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
- chip->enable_dma ? "DMA" : "PIO");
-
-@@ -1405,7 +1964,9 @@ static int setup(struct spi_device *spi)
- chip->read = u16_reader;
- chip->write = u16_writer;
- } else if (spi->bits_per_word <= 32) {
-+#ifndef CONFIG_GEN3_SPI
- chip->cr0 |= SSCR0_EDSS;
-+#endif
- chip->n_bytes = 4;
- chip->dma_width = DCMD_WIDTH4;
- chip->read = u32_reader;
-@@ -1438,94 +1999,6 @@ static void cleanup(struct spi_device *spi)
- kfree(chip);
- }
-
--static int init_queue(struct driver_data *drv_data)
--{
-- INIT_LIST_HEAD(&drv_data->queue);
-- spin_lock_init(&drv_data->lock);
--
-- drv_data->run = QUEUE_STOPPED;
-- drv_data->busy = 0;
--
-- tasklet_init(&drv_data->pump_transfers,
-- pump_transfers, (unsigned long)drv_data);
--
-- INIT_WORK(&drv_data->pump_messages, pump_messages);
-- drv_data->workqueue = create_singlethread_workqueue(
-- dev_name(drv_data->master->dev.parent));
-- if (drv_data->workqueue == NULL)
-- return -EBUSY;
--
-- return 0;
--}
--
--static int start_queue(struct driver_data *drv_data)
--{
-- unsigned long flags;
--
-- spin_lock_irqsave(&drv_data->lock, flags);
--
-- if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
-- spin_unlock_irqrestore(&drv_data->lock, flags);
-- return -EBUSY;
-- }
--
-- drv_data->run = QUEUE_RUNNING;
-- drv_data->cur_msg = NULL;
-- drv_data->cur_transfer = NULL;
-- drv_data->cur_chip = NULL;
-- spin_unlock_irqrestore(&drv_data->lock, flags);
--
-- queue_work(drv_data->workqueue, &drv_data->pump_messages);
--
-- return 0;
--}
--
--static int stop_queue(struct driver_data *drv_data)
--{
-- unsigned long flags;
-- unsigned limit = 500;
-- int status = 0;
--
-- spin_lock_irqsave(&drv_data->lock, flags);
--
-- /* This is a bit lame, but is optimized for the common execution path.
-- * A wait_queue on the drv_data->busy could be used, but then the common
-- * execution path (pump_messages) would be required to call wake_up or
-- * friends on every SPI message. Do this instead */
-- drv_data->run = QUEUE_STOPPED;
-- while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) {
-- spin_unlock_irqrestore(&drv_data->lock, flags);
-- msleep(10);
-- spin_lock_irqsave(&drv_data->lock, flags);
-- }
--
-- if (!list_empty(&drv_data->queue) || drv_data->busy)
-- status = -EBUSY;
--
-- spin_unlock_irqrestore(&drv_data->lock, flags);
--
-- return status;
--}
--
--static int destroy_queue(struct driver_data *drv_data)
--{
-- int status;
--
-- status = stop_queue(drv_data);
-- /* we are unloading the module or failing to load (only two calls
-- * to this routine), and neither call can handle a return value.
-- * However, destroy_workqueue calls flush_workqueue, and that will
-- * block until all work is done. If the reason that stop_queue
-- * timed out is that the work will never finish, then it does no
-- * good to call destroy_workqueue, so return anyway. */
-- if (status != 0)
-- return status;
--
-- destroy_workqueue(drv_data->workqueue);
--
-- return 0;
--}
--
- static int pxa2xx_spi_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
-@@ -1557,16 +2030,27 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
- drv_data->ssp = ssp;
-
- master->dev.parent = &pdev->dev;
-+#ifdef CONFIG_OF
-+#ifndef CONFIG_GEN3_SPI
- master->dev.of_node = pdev->dev.of_node;
-+#endif
-+#endif
-+
- /* the spi->mode bits understood by this driver: */
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
-+#else
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
--
-+#endif
- master->bus_num = pdev->id;
- master->num_chipselect = platform_info->num_chipselect;
- master->dma_alignment = DMA_ALIGNMENT;
- master->cleanup = cleanup;
- master->setup = setup;
-- master->transfer = transfer;
-+ master->prepare_transfer_hardware = prepare_transfer_hardware;
-+ master->transfer_one_message = transfer_one_message;
-+ master->unprepare_transfer_hardware = unprepare_transfer_hardware;
-+ master->rt = true;
-
- drv_data->ssp_type = ssp->type;
- drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data +
-@@ -1628,43 +2112,59 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
- clk_enable(ssp->clk);
-
- /* Load default SSP configuration */
-- write_SSCR0(0, drv_data->ioaddr);
-- write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
-- SSCR1_TxTresh(TX_THRESH_DFLT),
-- drv_data->ioaddr);
-- write_SSCR0(SSCR0_SCR(2)
-- | SSCR0_Motorola
-- | SSCR0_DataSize(8),
-- drv_data->ioaddr);
-+ write_sscr0(0, drv_data->ioaddr);
-+ switch (drv_data->ssp_type) {
-+ case CE5X00_SSP:
-+ write_sscr1(CE5X00_SSCR1_RxTresh(RX_THRESH_CE5X00_DFLT) |
-+ CE5X00_SSCR1_TxTresh(TX_THRESH_CE5X00_DFLT),
-+ drv_data->ioaddr);
-+#ifdef CONFIG_INTEL_QUARK_X1000_SOC
-+ /* using the Motorola SPI protocol and use 8 bit frame */
-+ write_sscr0(CE5X00_SSCR0_Motorola
-+ | CE5X00_SSCR0_DataSize(8),
-+ drv_data->ioaddr);
-+#else
-+ /* default using Motorola SPI protocol and use 8 bit frame */
-+ write_sscr0(SSCR0_SCR(2)
-+ | CE5X00_SSCR0_Motorola
-+ | CE5X00_SSCR0_DataSize(8),
-+ drv_data->ioaddr);
-+#endif
-+ break;
-+ case CE4100_SSP:
-+ case PXA25x_SSP:
-+ default:
-+ write_sscr1(SSCR1_RxTresh(RX_THRESH_DFLT) |
-+ SSCR1_TxTresh(TX_THRESH_DFLT),
-+ drv_data->ioaddr);
-+ write_sscr0(SSCR0_SCR(2)
-+ | SSCR0_Motorola
-+ | SSCR0_DataSize(8),
-+ drv_data->ioaddr);
-+ }
- if (!pxa25x_ssp_comp(drv_data))
-- write_SSTO(0, drv_data->ioaddr);
-- write_SSPSP(0, drv_data->ioaddr);
-+ write_ssto(0, drv_data->ioaddr);
-+#ifndef CONFIG_GEN3_SPI
-+ /*
-+ * SSPSP register is resrved on the CEXXXX SOCs.
-+ */
-+ write_sspsp(0, drv_data->ioaddr);
-+#endif
-
-- /* Initial and start queue */
-- status = init_queue(drv_data);
-- if (status != 0) {
-- dev_err(&pdev->dev, "problem initializing queue\n");
-- goto out_error_clock_enabled;
-- }
-- status = start_queue(drv_data);
-- if (status != 0) {
-- dev_err(&pdev->dev, "problem starting queue\n");
-- goto out_error_clock_enabled;
-- }
-+ /* Initialise transfer pump */
-+ tasklet_init(&drv_data->pump_transfers,
-+ pump_transfers, (unsigned long)drv_data);
-
- /* Register with the SPI framework */
- platform_set_drvdata(pdev, drv_data);
- status = spi_register_master(master);
- if (status != 0) {
- dev_err(&pdev->dev, "problem registering spi master\n");
-- goto out_error_queue_alloc;
-+ goto out_error_clock_enabled;
- }
-
- return status;
-
--out_error_queue_alloc:
-- destroy_queue(drv_data);
--
- out_error_clock_enabled:
- clk_disable(ssp->clk);
-
-@@ -1687,28 +2187,13 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
- {
- struct driver_data *drv_data = platform_get_drvdata(pdev);
- struct ssp_device *ssp;
-- int status = 0;
-
- if (!drv_data)
- return 0;
- ssp = drv_data->ssp;
-
-- /* Remove the queue */
-- status = destroy_queue(drv_data);
-- if (status != 0)
-- /* the kernel does not check the return status of this
-- * this routine (mod->exit, within the kernel). Therefore
-- * nothing is gained by returning from here, the module is
-- * going away regardless, and we should not leave any more
-- * resources allocated than necessary. We cannot free the
-- * message memory in drv_data->queue, but we can release the
-- * resources below. I think the kernel should honor -EBUSY
-- * returns but... */
-- dev_err(&pdev->dev, "pxa2xx_spi_remove: workqueue will not "
-- "complete, message memory not freed\n");
--
- /* Disable the SSP at the peripheral and SOC level */
-- write_SSCR0(0, drv_data->ioaddr);
-+ write_sscr0(0, drv_data->ioaddr);
- clk_disable(ssp->clk);
-
- /* Release DMA */
-@@ -1725,6 +2210,9 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
- /* Release SSP */
- pxa_ssp_free(ssp);
-
-+ /* Disable transfer pump */
-+ tasklet_disable(&drv_data->pump_transfers);
-+
- /* Disconnect from the SPI framework */
- spi_unregister_master(drv_data->master);
-
-@@ -1738,7 +2226,8 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev)
- {
- int status = 0;
-
-- if ((status = pxa2xx_spi_remove(pdev)) != 0)
-+ status = pxa2xx_spi_remove(pdev);
-+ if (status != 0)
- dev_err(&pdev->dev, "shutdown failed with %d\n", status);
- }
-
-@@ -1749,10 +2238,15 @@ static int pxa2xx_spi_suspend(struct device *dev)
- struct ssp_device *ssp = drv_data->ssp;
- int status = 0;
-
-- status = stop_queue(drv_data);
-- if (status != 0)
-+ status = spi_master_suspend(drv_data->master);
-+ if (status) {
-+ dev_warn(dev, "cannot suspend master\n");
- return status;
-- write_SSCR0(0, drv_data->ioaddr);
-+ }
-+
-+ pm_runtime_get_sync(dev);
-+
-+ write_sscr0(0, drv_data->ioaddr);
- clk_disable(ssp->clk);
-
- return 0;
-@@ -1774,14 +2268,14 @@ static int pxa2xx_spi_resume(struct device *dev)
- /* Enable the SSP clock */
- clk_enable(ssp->clk);
-
-+ pm_runtime_put(dev);
-+
- /* Start the queue running */
-- status = start_queue(drv_data);
-- if (status != 0) {
-+ status = spi_master_resume(drv_data->master);
-+ if (status)
- dev_err(dev, "problem starting queue (%d)\n", status);
-- return status;
-- }
-
-- return 0;
-+ return status;
- }
-
- static const struct dev_pm_ops pxa2xx_spi_pm_ops = {
-diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
-index 19ee901..493ce4a 100644
---- a/drivers/spi/spi.c
-+++ b/drivers/spi/spi.c
-@@ -1248,10 +1248,10 @@ int spi_master_resume(struct spi_master *master)
- }
- EXPORT_SYMBOL_GPL(spi_master_resume);
-
--static int __spi_master_match(struct device *dev, void *data)
-+static int __spi_master_match(struct device *dev, const void *data)
- {
- struct spi_master *m;
-- u16 *bus_num = data;
-+ const u16 *bus_num = data;
-
- m = container_of(dev, struct spi_master, dev);
- return m->bus_num == *bus_num;
-diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
-index fb8c239..1309fac 100644
---- a/drivers/staging/iio/adc/Kconfig
-+++ b/drivers/staging/iio/adc/Kconfig
-@@ -137,4 +137,17 @@ config SPEAR_ADC
- Say yes here to build support for the integrated ADC inside the
- ST SPEAr SoC. Provides direct access via sysfs.
-
-+config MAX78M6610_LMU
-+ tristate "Maxim 78M6610+LMU driver"
-+ depends on SPI
-+ select IIO_BUFFER
-+ select IIO_TRIGGERED_BUFFER
-+ help
-+ Say yes here to build support for Maxim Energy Measurement Processor
-+ for Load Monitoring Units.
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called max78m6610_lmu.
-+
-+
- endmenu
-diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
-index d285596..2c4e7e1 100644
---- a/drivers/staging/iio/adc/Makefile
-+++ b/drivers/staging/iio/adc/Makefile
-@@ -21,3 +21,4 @@ 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
-diff --git a/drivers/staging/iio/adc/max78m6610_lmu.c b/drivers/staging/iio/adc/max78m6610_lmu.c
-new file mode 100644
-index 0000000..5a72f8e
---- /dev/null
-+++ b/drivers/staging/iio/adc/max78m6610_lmu.c
-@@ -0,0 +1,1113 @@
-+/*
-+ * max78m6610+lmu SPI protocol driver
-+ *
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ *
-+ * This SPI protocol driver is developed for the Maxim 78M6610+LMU (eADC).
-+ * The driver is developed as a part of the Clanton BSP where integrated into
-+ * Clanton Evaluation Boards Cross Hill Industrial-E.
-+ *
-+ * The Maxim 78M6610+LMU is an energy measurement processor (EMP) for
-+ * load monitoring on single or spilt-phase AC loads. It supports varies
-+ * interface configuration protocols through I/O pins.
-+ *
-+ * With 3 wire serial input/output interfaces provided by Clanton SoC,
-+ * the 78M6610+LMU can be connected directly as SPI slave device.
-+ */
-+
-+#include <linux/iio/iio.h>
-+#include <linux/iio/buffer.h>
-+#include <linux/iio/types.h>
-+#include <linux/iio/trigger.h>
-+#include <linux/iio/trigger_consumer.h>
-+#include <linux/iio/triggered_buffer.h>
-+#include <linux/spi/spi.h>
-+#include <linux/spi/spidev.h>
-+#include <linux/version.h>
-+#include <linux/cdev.h>
-+#include <linux/fs.h>
-+
-+#define INSTAN_VA 0x33 /* instaneous Voltage for VA source */
-+#define INSTAN_IA 0x44 /* instaneous Current for IA source */
-+#define INSTAN_PA 0x5C /* instaneous Active Power for source A*/
-+#define INSTAN_PQA 0x5E /* instaneous Reactive Power for source A*/
-+#define VA_RMS 0x2B /* RMS voltage for VA source */
-+#define IA_RMS 0x3E /* RMS current for VA source */
-+#define WATT_A 0x4B /* Active Power for source A */
-+#define VAR_A 0x51 /* Reactive power for source A */
-+#define VA_A 0x4E /* Volt-Amperes for source A */
-+#define PFA 0x65 /* Source A Power Factor */
-+
-+#define INSTAN_VB 0x34 /* instaneous Voltage for VB source */
-+#define INSTAN_IB 0x45 /* instaneous Current for IB source */
-+#define INSTAN_PB 0x5D /* instaneous Active Power for source B*/
-+#define INSTAN_PQB 0x5F /* instaneous Voltage for VB source */
-+#define VB_RMS 0x2C /* RMS voltage for VB source */
-+#define IB_RMS 0x3F /* RMS current for VB source */
-+#define WATT_B 0x4C /* Active Power for source B */
-+#define VAR_B 0x52 /* Reactive power for source B */
-+#define VA_B 0x4F /* Volt-amperes for source B */
-+#define PFB 0x66 /* Source B Power Factor */
-+
-+/* Addr bit 6-7: ADDR6, ADDR7 */
-+#define SPI_CB_ADDR_MASK_7_6(x) (((x) & 0xC0) >> 6)
-+/* Addr bit 0 - 5 */
-+#define SPI_TB_ADDR_MASK_5_0(x) ((x) & 0x3F)
-+
-+#define SPI_CB_NBR_ACC 0x00 /* number register of accesss, limit to 1 */
-+#define SPI_CB_CMD 0x01 /* SPI command flag */
-+#define SPI_OP_READ 0x00 /* bit 1: Read/Write RD:0 W:1 */
-+#define SPI_OP_WRITE 0x02 /* bit 1: Read/Write RD:0 W:1 */
-+/* Positive / negative conversion */
-+#define SIGN_CONVERT 0xFFFFFFFFFFFFFFFF
-+#define DATA_BIT_MASK 0x00FFFFFF
-+#define SIGN_BIT_NUM 23
-+#define SPI_MSG_LEN 5
-+#define RX_OFFSET 1
-+#define SPI_BBUFFER_LEN 4096
-+
-+/* SPI message Control byte */
-+#define SPI_CB(x) ((SPI_CB_NBR_ACC << 4)\
-+ | (SPI_CB_ADDR_MASK_7_6(x) << 2)\
-+ | SPI_CB_CMD)
-+/* SPI message Transaction byte */
-+#define SPI_TB_READ(x) ((SPI_TB_ADDR_MASK_5_0(x) << 2)\
-+ | SPI_OP_READ)
-+
-+
-+/**
-+ * max78m6610_lmu_channels structure maps eADC measurement features to
-+ * correlates IIO channels
-+ */
-+static const struct iio_chan_spec max78m6610_lmu_channels[] = {
-+ /* IIO Channels for source A */
-+ {
-+ .type = IIO_VOLTAGE,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "inst",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_VA,
-+ .scan_index = 0,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_CURRENT,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "rms",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = IA_RMS,
-+ .scan_index = 1,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "inst_act",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_PA,
-+ .scan_index = 2,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "inst_react",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_PQA,
-+ .scan_index = 3,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "avg_act",
-+ /* IIO_CHAN_INFO_AVERAGE_RAW is not used here,
-+ * this average value is provide by HW register,
-+ */
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = WATT_A,
-+ .scan_index = 4,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "avg_react",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = VAR_A,
-+ .scan_index = 5,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "apparent",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = VA_A,
-+ .scan_index = 6,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "factor",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = PFA,
-+ .scan_index = 7,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32, /* data type S.22 */
-+ .storagebits = 32,
-+ .shift = 22,
-+ },
-+ },
-+ {
-+ .type = IIO_VOLTAGE,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "rms",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = VA_RMS,
-+ .scan_index = 8,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+
-+ /* IIO channels for source B */
-+ {
-+ .type = IIO_VOLTAGE,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "inst",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_VB,
-+ .scan_index = 9,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_CURRENT,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "rms",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = IB_RMS,
-+ .scan_index = 10,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "inst_act",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_PB,
-+ .scan_index = 11,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "inst_react",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_PQB,
-+ .scan_index = 12,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "avg_act",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = WATT_B,
-+ .scan_index = 13,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "avg_react",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = VAR_B,
-+ .scan_index = 14,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "apparent",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = VA_B,
-+ .scan_index = 15,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_POWER,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "factor",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = PFB,
-+ .scan_index = 16,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32, /* data type S.22 */
-+ .storagebits = 32,
-+ .shift = 22,
-+ },
-+ },
-+ {
-+ .type = IIO_VOLTAGE,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "rms",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = VB_RMS,
-+ .scan_index = 17,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_CURRENT,
-+ .indexed = 1,
-+ .channel = 0,
-+ .extend_name = "inst",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_IA,
-+ .scan_index = 18,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+ {
-+ .type = IIO_CURRENT,
-+ .indexed = 1,
-+ .channel = 1,
-+ .extend_name = "inst",
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
-+ .address = INSTAN_IB,
-+ .scan_index = 19,
-+ .scan_type = {
-+ .sign = 's',
-+ .realbits = 32,
-+ .storagebits = 32,
-+ .shift = 23,
-+ },
-+ },
-+
-+ IIO_CHAN_SOFT_TIMESTAMP(20),
-+};
-+
-+/* max number of iio channels */
-+#define MAX_CHAN_NUM ARRAY_SIZE(max78m6610_lmu_channels)
-+
-+/* eADC state structure */
-+struct max78m6610_lmu_state {
-+ struct spi_device *spi;
-+ struct iio_dev_attr *iio_attr;
-+ struct spi_transfer ring_xfer[MAX_CHAN_NUM];
-+ struct spi_transfer scan_single_xfer;
-+ struct spi_message ring_msg;
-+ struct spi_message scan_single_msg;
-+
-+ u8 tx_buf[SPI_MSG_LEN * MAX_CHAN_NUM];
-+ u8 rx_buf[SPI_MSG_LEN * MAX_CHAN_NUM + sizeof(s64)];
-+
-+
-+ /* Char dev to provide ioctl interface for f/w upgrade
-+ * or low-level register access */
-+ struct cdev cdev;
-+ dev_t cdev_no;
-+ struct class *cl;
-+ u8 *bbuffer;
-+};
-+
-+/**
-+ * ret_fraction_log2
-+ *
-+ * @param val: pointer to val
-+ * @param val2: pointer to val2
-+ * @return: no returns
-+ *
-+ * this function to re-implement of IIO_VAL_FRACTIONAL_LOG2 marco in IIO
-+ * because of the do_div() function is not correctly handle the negative
-+ * input value.
-+ */
-+static void ret_fraction_log2(int *val, int *val2)
-+{
-+ s64 tmp;
-+
-+ tmp = *val;
-+
-+ if (*val < 0) {
-+ pr_debug("%s: before shr: tmp=0x%016llX, *val=0x%08X, tmp=%lld, *val=%d\n",
-+ __func__, tmp, *val, tmp, *val);
-+ /* the do_div function will return trash if the value
-+ * of input is negative. We need to treat tmp as
-+ * a positive number for calculation.
-+ * 1. XOR tmp with 0xFFFFFFFFFFFFFFFF.
-+ * 2. add on the differential
-+ */
-+ tmp = (tmp ^ SIGN_CONVERT) + 1;
-+ tmp = tmp * 1000000000LL >> (*val2);
-+ *val2 = do_div(tmp, 1000000000LL);
-+ *val = tmp;
-+ /* the IIO_VAL_INT_PLUS_NANO marco is used in the later stage
-+ * to return the proper format of output.
-+ * The IIO use the value of val2 to determinate the sign
-+ * of the output.
-+ * Convert val2 from positive to negative to fool IIO to
-+ * display the
-+ * correct output format.
-+ */
-+ *val2 = *val2 ^ SIGN_CONVERT;
-+ pr_debug("%s: at the end: *val=0x%08x, tmp=%lld, *val=%d\n",
-+ __func__, *val, tmp, *val);
-+
-+ } else {
-+
-+ tmp = tmp * 1000000000LL >> (*val2);
-+ *val2 = do_div(tmp, 1000000000LL);
-+ *val = tmp;
-+ }
-+}
-+
-+/**
-+ * max78m6610_lmu_update_scan_mode
-+ *
-+ * @param indio_dev: iio_dev pointer.
-+ * @param active_scan_mask: pointer to scan mask.
-+ * @return 0 on success or standard errnos on failure
-+ *
-+ * setup the spi transfer buffer for the actived scan mask
-+ **/
-+static int max78m6610_lmu_update_scan_mode(struct iio_dev *indio_dev,
-+ const unsigned long *active_scan_mask)
-+{
-+ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
-+ int i, tx = 0, k = 0;
-+ unsigned addr;
-+
-+ spi_message_init(&st->ring_msg);
-+
-+ /* scan through all the channels */
-+ for (i = 0; i < MAX_CHAN_NUM; i++) {
-+ /* we build the the spi message here that support
-+ * multiple register access request on the selected channel */
-+ if (test_bit(i, active_scan_mask)) {
-+ addr = max78m6610_lmu_channels[i].address;
-+ /* first two bytes are the contol bytes */
-+ st->tx_buf[tx] = SPI_CB(addr);
-+ st->tx_buf[tx+1] = SPI_TB_READ(addr);
-+
-+ st->ring_xfer[k].cs_change = 0;
-+ st->ring_xfer[k].tx_buf = &st->tx_buf[tx];
-+ /* rx buffer */
-+ /* All the HW registers in the HW are designed as 24 bit
-+ * size, so we skip the first byte in the rx_buf when
-+ * constructing the ring_xfer.
-+ */
-+ st->ring_xfer[k].rx_buf = &st->rx_buf[tx];
-+ st->ring_xfer[k].len = SPI_MSG_LEN;
-+ st->ring_xfer[k].cs_change = 1;
-+
-+ spi_message_add_tail(&st->ring_xfer[k],
-+ &st->ring_msg);
-+ /* update in bytes number */
-+ tx += SPI_MSG_LEN;
-+ k++;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * max78m6610_lmu_trigger_handle
-+ *
-+ * @param irq: irq indicator
-+ * @parma p: iio pull funciton pointer
-+ * @return IRQ_HANDLED
-+ *
-+ * bh handler of trigger launched polling to ring buffer
-+ *
-+ **/
-+static irqreturn_t max78m6610_lmu_trigger_handler(int irq, void *p)
-+{
-+ struct iio_poll_func *pf = p;
-+ struct iio_dev *indio_dev = pf->indio_dev;
-+ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
-+
-+ u32 scan_buf[((sizeof(u32)*MAX_CHAN_NUM)+sizeof(s64))/sizeof(u32)];
-+ s64 time_ns = 0;
-+ int b_sent;
-+ int i = 0, rx_bit = 0;
-+ int scan_count;
-+
-+ b_sent = spi_sync(st->spi, &st->ring_msg);
-+ if (b_sent) {
-+ pr_err("spi_sync failed.\n");
-+ goto done;
-+ }
-+
-+ scan_count = bitmap_weight(indio_dev->active_scan_mask,
-+ indio_dev->masklength);
-+
-+ if (indio_dev->scan_timestamp) {
-+ time_ns = iio_get_time_ns();
-+ memcpy((u8 *)scan_buf + indio_dev->scan_bytes - sizeof(s64),
-+ &time_ns, sizeof(time_ns));
-+ }
-+
-+ for (i = 0; i < scan_count; i++) {
-+ u32 *rx_buf_32 = NULL;
-+ rx_bit = i*SPI_MSG_LEN + RX_OFFSET;
-+ rx_buf_32 = (u32 *)&(st->rx_buf[rx_bit]);
-+ *rx_buf_32 = be32_to_cpu(*rx_buf_32) & DATA_BIT_MASK;
-+ scan_buf[i] = sign_extend32(*rx_buf_32,
-+ SIGN_BIT_NUM);
-+ }
-+
-+ iio_push_to_buffers(indio_dev, (u8 *)scan_buf);
-+done:
-+ iio_trigger_notify_done(indio_dev->trig);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/**
-+ * max78m6610_lmu_scan_direct
-+ *
-+ * @param st: max78m6610 state structure pointer
-+ * @param addr: register address
-+ * @return: signed 32-bits result value or standard errno on failure.
-+ *
-+ * buildup SPI message to scan HW register based on input address.
-+ */
-+static int max78m6610_lmu_scan_direct(struct max78m6610_lmu_state *st,
-+ unsigned addr)
-+{
-+ int ret;
-+ u32 *rx_buf_32 = NULL;
-+
-+ pr_debug("build SPI request msg to addr 0x%02x\n", addr);
-+
-+ st->tx_buf[0] = SPI_CB(addr);
-+ st->tx_buf[1] = SPI_TB_READ(addr);
-+
-+ ret = spi_sync(st->spi, &st->scan_single_msg);
-+ if (ret) {
-+ pr_err("spi_sync return non-zero value\n");
-+ return -EIO;
-+ }
-+
-+ rx_buf_32 = (uint32_t *)&(st->rx_buf[RX_OFFSET]);
-+ *rx_buf_32 = be32_to_cpu(*rx_buf_32) & DATA_BIT_MASK;
-+
-+ ret = sign_extend32(*rx_buf_32, SIGN_BIT_NUM);
-+
-+ return ret;
-+}
-+
-+/**
-+ * max78m6610_lmu_read_raw
-+ *
-+ * @param indio_dev: iio_dev pointer
-+ * @param chan: pointer to iio channel spec struct
-+ * @param val: return value pointer
-+ * @param val2: return value 2 ponter
-+ * @parma m: read mask
-+ * @return: IIO value type
-+ *
-+ * This function will be invoked when request a value form the device.
-+ * Read mask specifies which value, return value will specify the type of
-+ * value returned from device, val and val2 will contains the elements
-+ * making up the return value.
-+ */
-+static int max78m6610_lmu_read_raw(struct iio_dev *indio_dev,
-+ struct iio_chan_spec const *chan,
-+ int *val,
-+ int *val2,
-+ long m)
-+{
-+ int ret;
-+ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
-+
-+ switch (m) {
-+
-+ case IIO_CHAN_INFO_RAW:
-+ mutex_lock(&indio_dev->mlock);
-+ if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
-+ ret = -EBUSY;
-+ return ret;
-+ } else {
-+ ret = max78m6610_lmu_scan_direct(st, chan->address);
-+ }
-+ mutex_unlock(&indio_dev->mlock);
-+
-+ *val = ret;
-+ *val2 = chan->scan_type.shift;
-+
-+ ret_fraction_log2(val, val2);
-+ return IIO_VAL_INT_PLUS_NANO;
-+
-+ /* the full scale units : -1.0 to 1-LSB (0x7FFFFF)
-+ * As an example, if 230V-peak at the input to the voltage
-+ * divider gives 250mV-peak at the chip input, one would get a
-+ * full scale register reading of 1 - LSB (0x7FFFFF) for
-+ * instaneous voltage.
-+ * Similarly, if 30Apk at the sensor input provides 250mV-peak
-+ * to the chip input, a full scale register value of 1 - LSB
-+ * (0x7FFFFF) for instanteous current would correspond to
-+ * 30 amps.
-+ * Full scale watts correspond to the result of full scale
-+ * current and voltage so, in this example, full scale watts
-+ * is 230 x 30 or 6900 watts.
-+ */
-+
-+ case IIO_CHAN_INFO_SCALE:
-+ switch (chan->type) {
-+ case IIO_CURRENT:
-+ *val = 250; /* unit mV */
-+ return IIO_VAL_INT;
-+
-+ case IIO_VOLTAGE:
-+ *val = 250; /* unit: mV */
-+ return IIO_VAL_INT;
-+
-+ case IIO_POWER:
-+ *val = 250*250; /* uV */
-+ return IIO_VAL_INT;
-+
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ }
-+ return -EINVAL;
-+}
-+
-+/* Driver specific iio info structure */
-+static const struct iio_info max78m6610_lmu_info = {
-+ .read_raw = max78m6610_lmu_read_raw,
-+ .update_scan_mode = max78m6610_lmu_update_scan_mode,
-+ .driver_module = THIS_MODULE,
-+};
-+
-+static int
-+max78m6610_lmu_open(struct inode *inode, struct file *filp)
-+{
-+ struct max78m6610_lmu_state *st;
-+ int ret = 0;
-+
-+ st = container_of(inode->i_cdev,
-+ struct max78m6610_lmu_state,
-+ cdev);
-+ filp->private_data = st;
-+
-+ if (!st->bbuffer) {
-+ st->bbuffer = kmalloc(SPI_BBUFFER_LEN, GFP_KERNEL);
-+ if (!st->bbuffer) {
-+ dev_dbg(&st->spi->dev, "open/ENOMEM\n");
-+ ret = -ENOMEM;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+static int
-+max78m6610_lmu_release(struct inode *inode, struct file *filp)
-+{
-+ struct max78m6610_lmu_state *st =
-+ (struct max78m6610_lmu_state *)filp->private_data;
-+
-+ kfree(st->bbuffer);
-+ st->bbuffer = NULL;
-+
-+ return 0;
-+}
-+
-+static int spidev_message(struct max78m6610_lmu_state *st,
-+ struct spi_ioc_transfer *u_xfers,
-+ unsigned n_xfers)
-+{
-+ struct spi_message msg;
-+ struct spi_transfer *k_xfers;
-+ struct spi_transfer *k_tmp;
-+ struct spi_ioc_transfer *u_tmp;
-+ unsigned n, total;
-+ u8 *buf;
-+ int status = -EFAULT;
-+
-+ spi_message_init(&msg);
-+ k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
-+ if (k_xfers == NULL)
-+ return -ENOMEM;
-+
-+ /* Construct spi_message, copying any tx data to bounce buffer.
-+ * We walk the array of user-provided transfers, using each one
-+ * to initialize a kernel version of the same transfer.
-+ */
-+ buf = st->bbuffer;
-+ total = 0;
-+ for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
-+ n;
-+ n--, k_tmp++, u_tmp++) {
-+ k_tmp->len = u_tmp->len;
-+
-+ total += k_tmp->len;
-+ if (total > SPI_BBUFFER_LEN) {
-+ status = -EMSGSIZE;
-+ goto done;
-+ }
-+
-+ if (u_tmp->rx_buf) {
-+ k_tmp->rx_buf = buf;
-+ if (!access_ok(VERIFY_WRITE, (u8 __user *)
-+ (uintptr_t) u_tmp->rx_buf,
-+ u_tmp->len))
-+ goto done;
-+ }
-+ if (u_tmp->tx_buf) {
-+ k_tmp->tx_buf = buf;
-+ if (copy_from_user(buf, (const u8 __user *)
-+ (uintptr_t) u_tmp->tx_buf,
-+ u_tmp->len))
-+ goto done;
-+ }
-+ buf += k_tmp->len;
-+
-+ k_tmp->cs_change = !!u_tmp->cs_change;
-+ k_tmp->bits_per_word = u_tmp->bits_per_word;
-+ k_tmp->delay_usecs = u_tmp->delay_usecs;
-+ k_tmp->speed_hz = u_tmp->speed_hz;
-+#ifdef VERBOSE
-+ dev_dbg(&st->spi->dev,
-+ " xfer len %zd %s%s%s%dbits %u usec %uHz\n",
-+ u_tmp->len,
-+ u_tmp->rx_buf ? "rx " : "",
-+ u_tmp->tx_buf ? "tx " : "",
-+ u_tmp->cs_change ? "cs " : "",
-+ u_tmp->bits_per_word ? : st->spi->bits_per_word,
-+ u_tmp->delay_usecs,
-+ u_tmp->speed_hz ? : st->spi->max_speed_hz);
-+#endif
-+ spi_message_add_tail(k_tmp, &msg);
-+ }
-+
-+ status = spi_sync(st->spi, &msg);
-+ if (status < 0)
-+ goto done;
-+
-+ /* copy any rx data out of bounce buffer */
-+ buf = st->bbuffer;
-+ for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
-+ if (u_tmp->rx_buf) {
-+ if (__copy_to_user((u8 __user *)
-+ (uintptr_t) u_tmp->rx_buf, buf,
-+ u_tmp->len)) {
-+ status = -EFAULT;
-+ goto done;
-+ }
-+ }
-+ buf += u_tmp->len;
-+ }
-+ status = total;
-+
-+done:
-+ kfree(k_xfers);
-+ return status;
-+}
-+
-+static long
-+max78m6610_lmu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-+{
-+ struct max78m6610_lmu_state *st = filp->private_data;
-+ struct iio_dev *indio_dev = spi_get_drvdata(st->spi);
-+ u32 tmp;
-+ unsigned n_ioc;
-+ struct spi_ioc_transfer *ioc;
-+ int ret = 0;
-+
-+ /* Check type and command number */
-+ if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
-+ return -ENOTTY;
-+
-+ /* Check access direction once here; don't repeat below.
-+ * IOC_DIR is from the user perspective, while access_ok is
-+ * from the kernel perspective; so they look reversed.
-+ */
-+ if (_IOC_DIR(cmd) & _IOC_READ)
-+ ret = !access_ok(VERIFY_WRITE,
-+ (void __user *)arg, _IOC_SIZE(cmd));
-+ if (ret == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
-+ ret = !access_ok(VERIFY_READ,
-+ (void __user *)arg, _IOC_SIZE(cmd));
-+ if (ret)
-+ return -EFAULT;
-+
-+ ret = mutex_lock_interruptible(&indio_dev->mlock);
-+ if (ret)
-+ return ret;
-+
-+ /* segmented and/or full-duplex I/O request */
-+ if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
-+ || _IOC_DIR(cmd) != _IOC_WRITE) {
-+ ret = -ENOTTY;
-+ goto exit;
-+ }
-+
-+ tmp = _IOC_SIZE(cmd);
-+ if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
-+ ret = -EINVAL;
-+ goto exit;
-+ }
-+ n_ioc = tmp / sizeof(struct spi_ioc_transfer);
-+ if (n_ioc == 0)
-+ goto exit;
-+
-+ /* copy into scratch area */
-+ ioc = kmalloc(tmp, GFP_KERNEL);
-+ if (!ioc) {
-+ ret = -ENOMEM;
-+ goto exit;
-+ }
-+ if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
-+ kfree(ioc);
-+ ret = -EFAULT;
-+ goto exit;
-+ }
-+
-+ /* translate to spi_message, execute */
-+ ret = spidev_message(st, ioc, n_ioc);
-+ kfree(ioc);
-+
-+exit:
-+ mutex_unlock(&indio_dev->mlock);
-+
-+ return ret;
-+}
-+
-+static const struct file_operations max78m6610_lmu_fops = {
-+ .owner = THIS_MODULE,
-+ .open = max78m6610_lmu_open,
-+ .release = max78m6610_lmu_release,
-+ .unlocked_ioctl = max78m6610_lmu_ioctl,
-+};
-+
-+static int
-+max78m6610_lmu_chrdev_init(struct max78m6610_lmu_state *st)
-+{
-+ int ret;
-+ struct device *dev;
-+
-+ ret = alloc_chrdev_region(&st->cdev_no, 0, 1,
-+ "max78m6610_lmu");
-+ if (ret) {
-+ pr_err("Failed to alloc chrdev: %d", ret);
-+ return ret;
-+ }
-+
-+ cdev_init(&st->cdev, &max78m6610_lmu_fops);
-+
-+ ret = cdev_add(&st->cdev, st->cdev_no, 1);
-+ if (ret) {
-+ pr_err("Failed to add cdev: %d", ret);
-+ unregister_chrdev_region(st->cdev_no, 1);
-+ return ret;
-+ }
-+
-+ st->cl = class_create(THIS_MODULE, "char");
-+ if (IS_ERR(st->cl)) {
-+ pr_err("Failed to create device class: %ld",
-+ PTR_ERR(st->cl));
-+ cdev_del(&st->cdev);
-+ unregister_chrdev_region(st->cdev_no, 1);
-+ return PTR_ERR(st->cl);
-+ }
-+
-+ dev = device_create(st->cl, NULL, st->cdev_no, NULL,
-+ "max78m6610_lmu");
-+ if (IS_ERR(dev)) {
-+ pr_err("Failed to create device: %ld",
-+ PTR_ERR(st->cl));
-+ class_destroy(st->cl);
-+ cdev_del(&st->cdev);
-+ unregister_chrdev_region(st->cdev_no, 1);
-+ return PTR_ERR(dev);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+max78m6610_lmu_chrdev_remove(struct max78m6610_lmu_state *st)
-+{
-+ device_destroy(st->cl, st->cdev_no);
-+ class_destroy(st->cl);
-+ cdev_del(&st->cdev);
-+ unregister_chrdev_region(st->cdev_no, 1);
-+
-+ return 0;
-+}
-+
-+/**
-+ * max78m6610_lmu_probe
-+ *
-+ * @param spi: spi device pointer
-+ * @return: return 0 or standard errorids if failure
-+ *
-+ * device driver probe funciton for iio_dev struct initialisation.
-+ */
-+static int max78m6610_lmu_probe(struct spi_device *spi)
-+{
-+ struct max78m6610_lmu_state *st;
-+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
-+ int ret;
-+
-+ if (indio_dev == NULL)
-+ return -ENOMEM;
-+ st = iio_priv(indio_dev);
-+
-+ 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 = max78m6610_lmu_channels;
-+ indio_dev->num_channels = ARRAY_SIZE(max78m6610_lmu_channels);
-+ indio_dev->info = &max78m6610_lmu_info;
-+
-+ /* Setup default message */
-+ st->scan_single_xfer.tx_buf = &st->tx_buf[0];
-+ st->scan_single_xfer.rx_buf = &st->rx_buf[0];
-+ st->scan_single_xfer.len = SPI_MSG_LEN;
-+
-+ 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,
-+ &max78m6610_lmu_trigger_handler, NULL);
-+ if (ret) {
-+ pr_err("triger buffer setup failed !\n");
-+ goto error_free;
-+ }
-+
-+ pr_debug("%s: alloc dev id: %d\n", __func__, indio_dev->id);
-+ ret = iio_device_register(indio_dev);
-+ if (ret)
-+ goto error_cleanup_ring;
-+
-+ ret = max78m6610_lmu_chrdev_init(st);
-+ if (ret)
-+ goto error_cleanup_ring;
-+
-+ return 0;
-+
-+error_cleanup_ring:
-+ iio_triggered_buffer_cleanup(indio_dev);
-+error_free:
-+ iio_device_free(indio_dev);
-+
-+ return ret;
-+}
-+
-+/**
-+ * max78m6610_lmu_remove
-+ *
-+ * @param spi: spi device pointer
-+ * @return: return 0
-+ *
-+ * iio device unregister & cleanup
-+ */
-+static int max78m6610_lmu_remove(struct spi_device *spi)
-+{
-+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
-+ struct max78m6610_lmu_state *st = iio_priv(indio_dev);
-+
-+ max78m6610_lmu_chrdev_remove(st);
-+ iio_device_unregister(indio_dev);
-+ iio_triggered_buffer_cleanup(indio_dev);
-+ iio_device_free(indio_dev);
-+
-+ return 0;
-+}
-+
-+static const struct spi_device_id max78m6610_lmu_id[] = {
-+ {"max78m6610_lmu", 0},
-+ {}
-+};
-+MODULE_DEVICE_TABLE(spi, max78m6610_lmu_id);
-+
-+static struct spi_driver max78m6610_lmu_driver = {
-+ .driver = {
-+ .name = "max78m6610_lmu",
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = max78m6610_lmu_probe,
-+ .remove = max78m6610_lmu_remove,
-+ .id_table = max78m6610_lmu_id,
-+};
-+
-+/**
-+ * max78m6610_lmu_init
-+ *
-+ * device driver module init
-+ */
-+static __init int max78m6610_lmu_init(void)
-+{
-+ int ret;
-+
-+ ret = spi_register_driver(&max78m6610_lmu_driver);
-+ if (ret < 0)
-+ return ret;
-+
-+ return 0;
-+}
-+module_init(max78m6610_lmu_init);
-+
-+/**
-+ * max78m6610_lmu_exit
-+ *
-+ * device driver module exit
-+ */
-+static __exit void max78m6610_lmu_exit(void)
-+{
-+ spi_unregister_driver(&max78m6610_lmu_driver);
-+}
-+module_exit(max78m6610_lmu_exit);
-+
-+
-+MODULE_AUTHOR("Kai Ji <kai.ji@emutex.com>");
-+MODULE_DESCRIPTION("Maxim 78M6610+LMU eADC");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig
-index 7d32075..e9e837d 100644
---- a/drivers/staging/iio/trigger/Kconfig
-+++ b/drivers/staging/iio/trigger/Kconfig
-@@ -29,6 +29,17 @@ config IIO_SYSFS_TRIGGER
-
- To compile this driver as a module, choose M here: the
- module will be called iio-trig-sysfs.
-+
-+config IIO_HRTIMER_TRIGGER
-+ tristate "HRTIMER trigger"
-+ #depends on HRTIMER
-+ select IRQ_WORK
-+ help
-+ Provides support for using HRTIMER entries as IIO triggers.
-+ If unsure, say N (but it's safe to say "Y").
-+
-+ To compile this driver as a module, choose M here: the
-+ module will be called iio-trig-hrtimer.
-
- config IIO_BFIN_TMR_TRIGGER
- tristate "Blackfin TIMER trigger"
-diff --git a/drivers/staging/iio/trigger/Makefile b/drivers/staging/iio/trigger/Makefile
-index b088b57..ad2f595 100644
---- a/drivers/staging/iio/trigger/Makefile
-+++ b/drivers/staging/iio/trigger/Makefile
-@@ -5,4 +5,5 @@
- obj-$(CONFIG_IIO_PERIODIC_RTC_TRIGGER) += iio-trig-periodic-rtc.o
- obj-$(CONFIG_IIO_GPIO_TRIGGER) += iio-trig-gpio.o
- obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
-+obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
- obj-$(CONFIG_IIO_BFIN_TMR_TRIGGER) += iio-trig-bfin-timer.o
-diff --git a/drivers/staging/iio/trigger/iio-trig-hrtimer.c b/drivers/staging/iio/trigger/iio-trig-hrtimer.c
-new file mode 100644
-index 0000000..3f7d5b8
---- /dev/null
-+++ b/drivers/staging/iio/trigger/iio-trig-hrtimer.c
-@@ -0,0 +1,282 @@
-+/*
-+ * Industrial I/O - hrtimer trigger support
-+ *
-+ * Copyright 2013 STMicroelectronics Inc.
-+ * Denis Ciocca <denis.ciocca@xxxxxx>
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License version 2 as published by
-+ * the Free Software Foundation.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/hrtimer.h>
-+#include <linux/ktime.h>
-+#include <linux/slab.h>
-+#include <linux/list.h>
-+
-+#include <linux/iio/iio.h>
-+#include <linux/iio/trigger.h>
-+
-+struct iio_hrtimer_trigger_data {
-+ struct iio_trigger *trig;
-+ struct hrtimer timer;
-+ struct list_head l;
-+ ktime_t period;
-+ u16 freq;
-+ int id;
-+};
-+
-+static LIST_HEAD(iio_hrtimer_trigger_list);
-+static DEFINE_MUTEX(iio_hrtimer_trigger_list_mut);
-+
-+static int iio_hrtimer_trigger_probe(int id);
-+static int iio_hrtimer_trigger_remove(int id);
-+
-+static ssize_t iio_sysfs_hrtimer_trig_add(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t len)
-+{
-+ int ret;
-+ unsigned long input;
-+
-+ ret = kstrtoul(buf, 10, &input);
-+ if (ret)
-+ return ret;
-+
-+ ret = iio_hrtimer_trigger_probe(input);
-+ if (ret)
-+ return ret;
-+
-+ return len;
-+}
-+static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_hrtimer_trig_add);
-+
-+static ssize_t iio_sysfs_hrtimer_trig_remove(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t len)
-+{
-+ int ret;
-+ unsigned long input;
-+
-+ ret = kstrtoul(buf, 10, &input);
-+ if (ret)
-+ return ret;
-+
-+ ret = iio_hrtimer_trigger_remove(input);
-+ if (ret)
-+ return ret;
-+
-+ return len;
-+}
-+static DEVICE_ATTR(remove_trigger, S_IWUSR,
-+ NULL, &iio_sysfs_hrtimer_trig_remove);
-+
-+static struct attribute *iio_hrtimer_trig_attrs[] = {
-+ &dev_attr_add_trigger.attr,
-+ &dev_attr_remove_trigger.attr,
-+ NULL,
-+};
-+
-+static const struct attribute_group iio_hrtimer_trig_group = {
-+ .attrs = iio_hrtimer_trig_attrs,
-+};
-+
-+static const struct attribute_group *iio_hrtimer_trig_groups[] = {
-+ &iio_hrtimer_trig_group,
-+ NULL,
-+};
-+
-+static struct device iio_hrtimer_trig_dev = {
-+ .bus = &iio_bus_type,
-+ .groups = iio_hrtimer_trig_groups,
-+};
-+
-+static int iio_hrtimer_trig_set_state(struct iio_trigger *trig, bool state)
-+{
-+ struct iio_hrtimer_trigger_data *trig_data =
-+ dev_get_drvdata(&trig->dev);
-+
-+ if (trig_data->freq == 0)
-+ return -EINVAL;
-+
-+ if (state)
-+ hrtimer_start(&trig_data->timer,
-+ trig_data->period, HRTIMER_MODE_REL);
-+ else
-+ hrtimer_cancel(&trig_data->timer);
-+
-+ return 0;
-+}
-+
-+static ssize_t iio_hrtimer_trigger_set_freq_value(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t len)
-+{
-+ int ret;
-+ u16 frequency;
-+ struct iio_trigger *trig = to_iio_trigger(dev);
-+ struct iio_hrtimer_trigger_data *trig_data =
-+ dev_get_drvdata(&trig->dev);
-+
-+ ret = kstrtou16(buf, 10, &frequency);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (frequency > NSEC_PER_SEC)
-+ return -EINVAL;
-+
-+ trig_data->freq = frequency;
-+
-+ if (frequency)
-+ trig_data->period =
-+ ktime_set(0, NSEC_PER_SEC / trig_data->freq);
-+
-+ return len;
-+}
-+
-+static ssize_t iio_hrtimer_trigger_get_freq_value(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct iio_trigger *trig = to_iio_trigger(dev);
-+ struct iio_hrtimer_trigger_data *trig_data =
-+ dev_get_drvdata(&trig->dev);
-+
-+ return sprintf(buf, "%hu\n", trig_data->freq);
-+}
-+
-+static DEVICE_ATTR(frequency, S_IWUSR | S_IRUGO,
-+ iio_hrtimer_trigger_get_freq_value,
-+ iio_hrtimer_trigger_set_freq_value);
-+
-+static struct attribute *iio_hrtimer_trigger_attrs[] = {
-+ &dev_attr_frequency.attr,
-+ NULL,
-+};
-+
-+static const struct attribute_group iio_hrtimer_trigger_attr_group = {
-+ .attrs = iio_hrtimer_trigger_attrs,
-+};
-+
-+static const struct attribute_group *iio_hrtimer_trigger_attr_groups[] = {
-+ &iio_hrtimer_trigger_attr_group,
-+ NULL,
-+};
-+
-+static const struct iio_trigger_ops iio_hrtimer_trigger_ops = {
-+ .owner = THIS_MODULE,
-+ .set_trigger_state = &iio_hrtimer_trig_set_state,
-+};
-+
-+enum hrtimer_restart iio_hrtimer_trigger_func(struct hrtimer *timer)
-+{
-+ struct iio_hrtimer_trigger_data *trig_data;
-+
-+ trig_data = container_of(timer, struct iio_hrtimer_trigger_data, timer);
-+
-+ hrtimer_forward_now(timer, trig_data->period);
-+ iio_trigger_poll(trig_data->trig, 0);
-+
-+ return HRTIMER_RESTART;
-+}
-+
-+static int iio_hrtimer_trigger_probe(int id)
-+{
-+ int err;
-+ bool foundit = false;
-+ struct iio_hrtimer_trigger_data *trig_data;
-+
-+ mutex_lock(&iio_hrtimer_trigger_list_mut);
-+ list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
-+ if (id == trig_data->id) {
-+ foundit = true;
-+ break;
-+ }
-+ }
-+ if (foundit) {
-+ err = -EINVAL;
-+ goto iio_hrtimer_mutex_unlock;
-+ }
-+
-+ trig_data = kmalloc(sizeof(*trig_data), GFP_KERNEL);
-+ if (trig_data == NULL) {
-+ err = -ENOMEM;
-+ goto iio_hrtimer_mutex_unlock;
-+ }
-+
-+ trig_data->id = id;
-+ trig_data->trig = iio_trigger_alloc("hrtimer_trig%d", id);
-+ if (!trig_data->trig) {
-+ err = -ENOMEM;
-+ goto iio_hrtimer_free_trig_data;
-+ }
-+
-+ trig_data->trig->dev.groups = iio_hrtimer_trigger_attr_groups;
-+ trig_data->trig->ops = &iio_hrtimer_trigger_ops;
-+ trig_data->trig->dev.parent = &iio_hrtimer_trig_dev;
-+ dev_set_drvdata(&trig_data->trig->dev, trig_data);
-+
-+ trig_data->freq = 0;
-+ hrtimer_init(&trig_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-+ trig_data->timer.function = &iio_hrtimer_trigger_func;
-+
-+ err = iio_trigger_register(trig_data->trig);
-+ if (err)
-+ goto iio_hrtimer_free_trig_data;
-+
-+ list_add(&trig_data->l, &iio_hrtimer_trigger_list);
-+ __module_get(THIS_MODULE);
-+ mutex_unlock(&iio_hrtimer_trigger_list_mut);
-+
-+ return 0;
-+
-+iio_hrtimer_free_trig_data:
-+ kfree(trig_data);
-+iio_hrtimer_mutex_unlock:
-+ mutex_unlock(&iio_hrtimer_trigger_list_mut);
-+ return err;
-+}
-+
-+static int iio_hrtimer_trigger_remove(int id)
-+{
-+ bool foundit = false;
-+ struct iio_hrtimer_trigger_data *trig_data;
-+
-+ mutex_lock(&iio_hrtimer_trigger_list_mut);
-+ list_for_each_entry(trig_data, &iio_hrtimer_trigger_list, l) {
-+ if (id == trig_data->id) {
-+ foundit = true;
-+ break;
-+ }
-+ }
-+ if (!foundit) {
-+ mutex_unlock(&iio_hrtimer_trigger_list_mut);
-+ return -EINVAL;
-+ }
-+
-+ iio_trigger_unregister(trig_data->trig);
-+ iio_trigger_free(trig_data->trig);
-+
-+ list_del(&trig_data->l);
-+ kfree(trig_data);
-+ module_put(THIS_MODULE);
-+ mutex_unlock(&iio_hrtimer_trigger_list_mut);
-+
-+ return 0;
-+}
-+
-+static int __init iio_hrtimer_trig_init(void)
-+{
-+ device_initialize(&iio_hrtimer_trig_dev);
-+ dev_set_name(&iio_hrtimer_trig_dev, "iio_hrtimer_trigger");
-+ return device_add(&iio_hrtimer_trig_dev);
-+}
-+module_init(iio_hrtimer_trig_init);
-+
-+static void __exit iio_hrtimer_trig_exit(void)
-+{
-+ device_unregister(&iio_hrtimer_trig_dev);
-+}
-+module_exit(iio_hrtimer_trig_exit);
-+
-+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@xxxxxx>");
-+MODULE_DESCRIPTION("Hrtimer trigger for the iio subsystem");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
-index 733f22c..5f85dde 100644
---- a/drivers/tty/serial/8250/8250.c
-+++ b/drivers/tty/serial/8250/8250.c
-@@ -561,6 +561,59 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
- }
- }
-
-+/* Uart divisor latch read */
-+static inline int _serial_dl_read(struct uart_8250_port *up)
-+{
-+ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
-+}
-+
-+/* Uart divisor latch write */
-+static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-+{
-+ serial_out(up, UART_DLL, value & 0xff);
-+ serial_out(up, UART_DLM, value >> 8 & 0xff);
-+}
-+
-+#if defined(CONFIG_MIPS_ALCHEMY)
-+/* Au1x00 haven't got a standard divisor latch */
-+static int serial_dl_read(struct uart_8250_port *up)
-+{
-+ if (up->port.iotype == UPIO_AU)
-+ return __raw_readl(up->port.membase + 0x28);
-+ else
-+ return _serial_dl_read(up);
-+}
-+
-+static void serial_dl_write(struct uart_8250_port *up, int value)
-+{
-+ if (up->port.iotype == UPIO_AU)
-+ __raw_writel(value, up->port.membase + 0x28);
-+ else
-+ _serial_dl_write(up, value);
-+}
-+#elif defined(CONFIG_SERIAL_8250_RM9K)
-+static int serial_dl_read(struct uart_8250_port *up)
-+{
-+ return (up->port.iotype == UPIO_RM9000) ?
-+ (((__raw_readl(up->port.membase + 0x10) << 8) |
-+ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
-+ _serial_dl_read(up);
-+}
-+
-+static void serial_dl_write(struct uart_8250_port *up, int value)
-+{
-+ if (up->port.iotype == UPIO_RM9000) {
-+ __raw_writel(value, up->port.membase + 0x08);
-+ __raw_writel(value >> 8, up->port.membase + 0x10);
-+ } else {
-+ _serial_dl_write(up, value);
-+ }
-+}
-+#else
-+#define serial_dl_read(up) _serial_dl_read(up)
-+#define serial_dl_write(up, value) _serial_dl_write(up, value)
-+#endif
-+
- /*
- * For the 16C950
- */
-diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
-index 5cdb092..9f5d030 100644
---- a/drivers/tty/serial/8250/8250_pci.c
-+++ b/drivers/tty/serial/8250/8250_pci.c
-@@ -27,7 +27,13 @@
-
- #include "8250.h"
-
--#undef SERIAL_DEBUG_PCI
-+/* CLANTON FPGA */
-+#define SERIAL_DEBUG_PCI
-+
-+/* TODO: Bryan remove ! */
-+static unsigned int clanton_enable_msi = 0;
-+module_param(clanton_enable_msi, uint, 0644);
-+MODULE_PARM_DESC(clanton_enable_msi, "Enable MSI operation on Clanton 8250-PCI");
-
- /*
- * init function returns:
-@@ -156,6 +162,20 @@ afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
- }
-
- /*
-+ * UART parameters for Intel Clanton setup
-+ */
-+static int
-+pci_intel_cln_setup(struct serial_private *priv,
-+ const struct pciserial_board *board,
-+ struct uart_8250_port *port, int idx)
-+{
-+ unsigned int bar, offset = board->first_offset;
-+ bar = FL_GET_BASE(board->flags);
-+
-+ return setup_port(priv, port, bar, offset, board->reg_shift);
-+}
-+
-+/*
- * HP's Remote Management Console. The Diva chip came in several
- * different versions. N-class, L2000 and A500 have two Diva chips, each
- * with 3 UARTs (the third UART on the second chip is unused). Superdome
-@@ -1410,6 +1430,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
- .subdevice = PCI_ANY_ID,
- .setup = kt_serial_setup,
- },
-+ {
-+ .vendor = PCI_VENDOR_ID_INTEL,
-+ .device = 0x0936,
-+ .subvendor = PCI_ANY_ID,
-+ .subdevice = PCI_ANY_ID,
-+ .setup = pci_intel_cln_setup,
-+ },
-+
- /*
- * ITE
- */
-@@ -2139,6 +2167,8 @@ enum pci_board_num_t {
- pbn_oxsemi_2_4000000,
- pbn_oxsemi_4_4000000,
- pbn_oxsemi_8_4000000,
-+ pbn_intel_cb,
-+ pbn_intel_cln,
- pbn_intel_i960,
- pbn_sgi_ioc3,
- pbn_computone_4,
-@@ -2725,6 +2755,12 @@ static struct pciserial_board pci_boards[] = {
- .reg_shift = 2,
- .first_offset = 0x10000,
- },
-+ [pbn_intel_cln] = {
-+ .flags = FL_BASE0,
-+ .num_ports = 1,
-+ .base_baud = 2764800,
-+ .reg_shift = 2,
-+ },
- [pbn_sgi_ioc3] = {
- .flags = FL_BASE0|FL_NOIRQ,
- .num_ports = 1,
-@@ -3187,6 +3223,14 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
- if (rc)
- return rc;
-
-+ /* TODO: Bryan remove ! */
-+ if(clanton_enable_msi == 1){
-+ if(pci_enable_msi(dev)!=0){
-+ printk(KERN_ERR "CLANTON/DEBUG unable to enable MSIs on serial port!\n");
-+ }
-+ }
-+
-+
- if (ent->driver_data == pbn_default) {
- /*
- * Use a copy of the pci_board entry for this;
-@@ -3998,6 +4042,12 @@ static struct pci_device_id serial_pci_tbl[] = {
- { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- pbn_b2_bt_2_115200 },
-+ /*
-+ * Clanton descriptor
-+ */
-+ { PCI_VENDOR_ID_INTEL, 0x0936,
-+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+ pbn_intel_cln },
-
- /*
- * EKF addition for i960 Boards form EKF with serial port
-diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
-index 02e706e..3a60e64 100644
---- a/drivers/tty/serial/Kconfig
-+++ b/drivers/tty/serial/Kconfig
-@@ -1327,6 +1327,26 @@ config SERIAL_IFX6X60
- help
- Support for the IFX6x60 modem devices on Intel MID platforms.
-
-+config SERIAL_QUARK_UART
-+ tristate "Quark High Speed UART support"
-+ depends on PCI
-+ select SERIAL_CORE
-+ select DMADEVICES
-+ select INTEL_MID_DMAC
-+ help
-+ This driver is for Intel(R) Quark X1000 UART with DMA enabled.
-+ If you don't want DMA then you should use the standard 8250_pci
-+ driver.
-+
-+config SERIAL_QUARK_UART_CONSOLE
-+ bool "Support for console on Intel(R) Quark X1000 UART"
-+ depends on SERIAL_QUARK_UART=y
-+ select SERIAL_CORE_CONSOLE
-+ help
-+ Say Y here if you wish to use the Clanton UART as the system console
-+ (the system console is the device which receives all kernel messages and
-+ warnings and which allows logins in single user mode).
-+
- config SERIAL_PCH_UART
- tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
- depends on PCI
-diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
-index df1b998..ccbc063 100644
---- a/drivers/tty/serial/Makefile
-+++ b/drivers/tty/serial/Makefile
-@@ -74,6 +74,7 @@ obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
- obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
- obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
- obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
-+obj-$(CONFIG_SERIAL_QUARK_UART) += intel_quark_uart.o
- obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
- 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..1377bdd
---- /dev/null
-+++ b/drivers/tty/serial/intel_quark_uart.c
-@@ -0,0 +1,2032 @@
-+/*
-+ *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
-+ *Copyright (C) 2014 Intel Corporation.
-+ *
-+ *This program is free software; you can redistribute it and/or modify
-+ *it under the terms of the GNU General Public License as published by
-+ *the Free Software Foundation; version 2 of the License.
-+ *
-+ *This program is distributed in the hope that it will be useful,
-+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ *GNU General Public License for more details.
-+ *
-+ *You should have received a copy of the GNU General Public License
-+ *along with this program; if not, write to the Free Software
-+ *Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
-+ */
-+#if defined(CONFIG_SERIAL_QUARK_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-+#define SUPPORT_SYSRQ
-+#endif
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+#include <asm/cln.h>
-+#endif
-+#include <linux/kernel.h>
-+#include <linux/serial_reg.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/pci.h>
-+#include <linux/console.h>
-+#include <linux/serial_core.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/dmi.h>
-+#include <linux/nmi.h>
-+#include <linux/delay.h>
-+#include <linux/intel_mid_dma.h>
-+#include <linux/debugfs.h>
-+#include <linux/dmaengine.h>
-+
-+enum {
-+ QUARK_UART_HANDLED_RX_INT_SHIFT,
-+ QUARK_UART_HANDLED_TX_INT_SHIFT,
-+ QUARK_UART_HANDLED_RX_ERR_INT_SHIFT,
-+ QUARK_UART_HANDLED_RX_TRG_INT_SHIFT,
-+ QUARK_UART_HANDLED_MS_INT_SHIFT,
-+ QUARK_UART_HANDLED_LS_INT_SHIFT,
-+};
-+
-+enum {
-+ QUARK_UART_8LINE,
-+ QUARK_UART_2LINE,
-+};
-+
-+#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), \
-+ })
-+
-+#define QUARK_UART_DRIVER_DEVICE "ttyQRK"
-+#define QUARK_UART_FIFO_LEN 16
-+//#define __QRK_DMA_DEBUG /* TODO: remove all code of this type */
-+
-+/* Set the max number of UART port
-+ * Intel EG20T QUARK: 4 port
-+ * LAPIS Semiconductor ML7213 IOH: 3 port
-+ * LAPIS Semiconductor ML7223 IOH: 2 port
-+*/
-+#define QUARK_UART_NR 2
-+
-+#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<<((\
-+ QUARK_UART_HANDLED_RX_ERR_INT_SHIFT)<<1))
-+#define QUARK_UART_HANDLED_RX_TRG_INT (1<<((\
-+ QUARK_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
-+#define QUARK_UART_HANDLED_MS_INT (1<<((QUARK_UART_HANDLED_MS_INT_SHIFT)<<1))
-+
-+#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_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_IID 0x00000006
-+#define QUARK_UART_IIR_MSI 0x00000000
-+#define QUARK_UART_IIR_TRI 0x00000002
-+#define QUARK_UART_IIR_RRI 0x00000004
-+#define QUARK_UART_IIR_REI 0x00000006
-+#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_FCR_FIFOE 0x00000001
-+#define QUARK_UART_FCR_RFR 0x00000002
-+#define QUARK_UART_FCR_TFR 0x00000004
-+#define QUARK_UART_FCR_DMS 0x00000008
-+#define QUARK_UART_FCR_FIFO256 0x00000020
-+#define QUARK_UART_FCR_RFTL 0x000000C0
-+
-+#define QUARK_UART_FCR_RFTL1 0x00000000
-+#define QUARK_UART_FCR_RFTL64 0x00000040
-+#define QUARK_UART_FCR_RFTL128 0x00000080
-+#define QUARK_UART_FCR_RFTL224 0x000000C0
-+#define QUARK_UART_FCR_RFTL16 QUARK_UART_FCR_RFTL64
-+#define QUARK_UART_FCR_RFTL32 QUARK_UART_FCR_RFTL128
-+#define QUARK_UART_FCR_RFTL56 QUARK_UART_FCR_RFTL224
-+#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_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_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)
-+
-+#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_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_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_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_MS (QUARK_UART_IIR_MSI)
-+
-+#define QUARK_UART_HAL_PARITY_NONE (QUARK_UART_LCR_NP)
-+#define QUARK_UART_HAL_PARITY_ODD (QUARK_UART_LCR_OP)
-+#define QUARK_UART_HAL_PARITY_EVEN (QUARK_UART_LCR_EP)
-+#define QUARK_UART_HAL_PARITY_FIX1 (QUARK_UART_LCR_1P)
-+#define QUARK_UART_HAL_PARITY_FIX0 (QUARK_UART_LCR_0P)
-+#define QUARK_UART_HAL_5BIT (QUARK_UART_LCR_5BIT)
-+#define QUARK_UART_HAL_6BIT (QUARK_UART_LCR_6BIT)
-+#define QUARK_UART_HAL_7BIT (QUARK_UART_LCR_7BIT)
-+#define QUARK_UART_HAL_8BIT (QUARK_UART_LCR_8BIT)
-+#define QUARK_UART_HAL_STB1 0
-+#define QUARK_UART_HAL_STB2 (QUARK_UART_LCR_STB)
-+
-+#define QUARK_UART_HAL_CLR_TX_FIFO (QUARK_UART_FCR_TFR)
-+#define QUARK_UART_HAL_CLR_RX_FIFO (QUARK_UART_FCR_RFR)
-+#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_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_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_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_MS_INT (QUARK_UART_IER_EDSSI)
-+#define QUARK_UART_HAL_ALL_INT (QUARK_UART_IER_MASK)
-+
-+#define QUARK_UART_HAL_DTR (QUARK_UART_MCR_DTR)
-+#define QUARK_UART_HAL_RTS (QUARK_UART_MCR_RTS)
-+#define QUARK_UART_HAL_OUT (QUARK_UART_MCR_OUT)
-+#define QUARK_UART_HAL_LOOP (QUARK_UART_MCR_LOOP)
-+#define QUARK_UART_HAL_AFE (QUARK_UART_MCR_AFE)
-+
-+#define PCI_VENDOR_ID_ROHM 0x10DB
-+
-+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-+
-+#define DEFAULT_UARTCLK 44236800 /* 2.76 MHz * 16 */
-+
-+/**
-+ * struct inel_cln_uart_buffer
-+ *
-+ * Descriptor for a UART bufer
-+ */
-+struct quark_uart_buffer {
-+ dma_addr_t dma_addr;
-+ unsigned char *buf;
-+ u32 offs;
-+ int size;
-+};
-+
-+struct x1000_port {
-+ struct uart_port port;
-+ int port_type;
-+ void __iomem *membase;
-+ resource_size_t mapbase;
-+ struct pci_dev *pdev;
-+ int fifo_size;
-+ unsigned int uartclk;
-+ int start_tx;
-+ int start_rx;
-+ int tx_empty;
-+ int trigger;
-+ int trigger_level;
-+ unsigned int dmsr;
-+ unsigned int fcr;
-+ unsigned int mcr;
-+ unsigned int 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 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;
-+
-+ /* protect the x1000_port private structure and io access to membase */
-+ spinlock_t lock;
-+};
-+
-+/**
-+ * struct quark_uart_driver_data - private data structure for UART-DMA
-+ * @port_type: The number of DMA channel
-+ * @line_no: UART port line number (0, 1, 2...)
-+ */
-+struct quark_uart_driver_data {
-+ int port_type;
-+ int line_no;
-+};
-+
-+#if 0
-+static unsigned int mem_serial_in(struct uart_port *p, int offset)
-+{
-+ offset = offset << p->regshift;
-+ return readb(p->membase + offset);
-+}
-+
-+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
-+ *
-+ * @param up: pointer to uart descriptor
-+ * @param offset: register offset
-+ *
-+ * Reads a register @ offset
-+ */
-+static inline unsigned int serial_in(struct x1000_port *up, int offset)
-+{
-+ int soffset = offset << 2;
-+
-+ return (unsigned int)readb(up->membase + soffset);
-+}
-+
-+/**
-+ * serial_out
-+ *
-+ * @param up: pointer to uart descriptor
-+ * @param offset: register offset
-+ *
-+ * Writes a register @ offset
-+ */
-+static inline void serial_out(struct x1000_port *up, int offset, int value)
-+{
-+ unsigned char val = value & 0xff;
-+ int soffset = offset << 2;
-+
-+ writeb(val, up->membase + soffset);
-+}
-+
-+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
-+static struct x1000_port *quark_uart_ports[QUARK_UART_NR];
-+#endif
-+static unsigned int default_baud = 115200;
-+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 };
-+static const int trigger_level_1[4] = { 1, 1, 1, 1 };
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+#define QUARK_REGS_BUFSIZE 1024
-+
-+
-+static ssize_t port_show_regs(struct file *file, char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct x1000_port *priv = file->private_data;
-+ char *buf;
-+ u32 len = 0;
-+ ssize_t ret;
-+ unsigned char lcr;
-+
-+ buf = kzalloc(QUARK_REGS_BUFSIZE, GFP_KERNEL);
-+ if (!buf)
-+ return 0;
-+
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "QUARK X1000 port[%d] regs:\n", priv->port.line);
-+
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "=================================\n");
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "IER: \t0x%02x\n", serial_in(priv, UART_IER));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "IIR: \t0x%02x\n", serial_in(priv, UART_IIR));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "LCR: \t0x%02x\n", serial_in(priv, UART_LCR));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "MCR: \t0x%02x\n", serial_in(priv, UART_MCR));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "LSR: \t0x%02x\n", serial_in(priv, UART_LSR));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "MSR: \t0x%02x\n", serial_in(priv, UART_MSR));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "BRCSR: \t0x%02x\n",
-+ serial_in(priv, QUARK_UART_BRCSR));
-+
-+ lcr = serial_in(priv, UART_LCR);
-+ serial_out(priv, UART_LCR, QUARK_UART_LCR_DLAB);
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "DLL: \t0x%02x\n", serial_in(priv, UART_DLL));
-+ len += snprintf(buf + len, QUARK_REGS_BUFSIZE - len,
-+ "DLM: \t0x%02x\n", serial_in(priv, UART_DLM));
-+ serial_out(priv, UART_LCR, lcr);
-+
-+ if (len > QUARK_REGS_BUFSIZE)
-+ len = QUARK_REGS_BUFSIZE;
-+
-+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+ kfree(buf);
-+ return ret;
-+}
-+
-+static const struct file_operations port_regs_ops = {
-+ .owner = THIS_MODULE,
-+ .open = simple_open,
-+ .read = port_show_regs,
-+ .llseek = default_llseek,
-+};
-+#endif /* CONFIG_DEBUG_FS */
-+
-+/* Return UART clock, checking for board specific clocks. */
-+static unsigned int quark_uart_get_uartclk(void)
-+{
-+ return DEFAULT_UARTCLK;
-+}
-+
-+static void quark_uart_hal_enable_interrupt(struct x1000_port *priv,
-+ 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;
-+ 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);
-+ serial_out(priv, UART_IER, ier);
-+}
-+
-+static int quark_uart_hal_set_line(struct x1000_port *priv, unsigned int baud,
-+ unsigned int parity, unsigned int bits,
-+ unsigned int stb)
-+{
-+ unsigned int dll, dlm, lcr;
-+ int div;
-+
-+ div = DIV_ROUND_CLOSEST(priv->uartclk / 16, baud);
-+ if (div < 0 || USHRT_MAX <= div) {
-+ dev_err(priv->port.dev, "Invalid Baud(div=0x%x)\n", div);
-+ return -EINVAL;
-+ }
-+
-+ dll = (unsigned int)div & 0x00FFU;
-+ dlm = ((unsigned int)div >> 8) & 0x00FFU;
-+
-+ if (parity & ~(QUARK_UART_LCR_PEN | QUARK_UART_LCR_EPS | QUARK_UART_LCR_SP)) {
-+ dev_err(priv->port.dev, "Invalid parity(0x%x)\n", parity);
-+ return -EINVAL;
-+ }
-+
-+ if (bits & ~QUARK_UART_LCR_WLS) {
-+ dev_err(priv->port.dev, "Invalid bits(0x%x)\n", bits);
-+ return -EINVAL;
-+ }
-+
-+ if (stb & ~QUARK_UART_LCR_STB) {
-+ dev_err(priv->port.dev, "Invalid STB(0x%x)\n", stb);
-+ return -EINVAL;
-+ }
-+
-+ lcr = parity;
-+ 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);
-+ serial_out(priv, UART_LCR, lcr);
-+
-+ return 0;
-+}
-+
-+static int quark_uart_hal_fifo_reset(struct x1000_port *priv,
-+ unsigned int flag)
-+{
-+ if (flag & ~(QUARK_UART_FCR_TFR | QUARK_UART_FCR_RFR)) {
-+ dev_err(priv->port.dev, "%s:Invalid flag(0x%x)\n",
-+ __func__, flag);
-+ return -EINVAL;
-+ }
-+
-+ serial_out(priv, UART_FCR, QUARK_UART_FCR_FIFOE | priv->fcr);
-+ serial_out(priv,
-+ UART_FCR, QUARK_UART_FCR_FIFOE | priv->fcr | flag);
-+ serial_out(priv, UART_FCR, priv->fcr);
-+
-+ return 0;
-+}
-+
-+static int quark_uart_hal_set_fifo(struct x1000_port *priv,
-+ unsigned int dmamode,
-+ unsigned int fifo_size, unsigned int trigger)
-+{
-+ u8 fcr;
-+
-+ if (dmamode & ~QUARK_UART_FCR_DMS) {
-+ dev_err(priv->port.dev, "%s:Invalid DMA Mode(0x%x)\n",
-+ __func__, dmamode);
-+ return -EINVAL;
-+ }
-+
-+ if (fifo_size & ~(QUARK_UART_FCR_FIFOE | QUARK_UART_FCR_FIFO256)) {
-+ dev_err(priv->port.dev, "%s:Invalid FIFO SIZE(0x%x)\n",
-+ __func__, fifo_size);
-+ return -EINVAL;
-+ }
-+
-+ if (trigger & ~QUARK_UART_FCR_RFTL) {
-+ dev_err(priv->port.dev, "%s:Invalid TRIGGER(0x%x)\n",
-+ __func__, trigger);
-+ return -EINVAL;
-+ }
-+
-+ switch (priv->fifo_size) {
-+ case 256:
-+ priv->trigger_level =
-+ trigger_level_256[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
-+ break;
-+ case 64:
-+ priv->trigger_level =
-+ trigger_level_64[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
-+ break;
-+ case 16:
-+ priv->trigger_level =
-+ trigger_level_16[trigger >> QUARK_UART_FCR_RFTL_SHIFT];
-+ break;
-+ default:
-+ priv->trigger_level =
-+ 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;
-+}
-+
-+static u8 quark_uart_hal_get_modem(struct x1000_port *priv)
-+{
-+ unsigned int msr = serial_in(priv, UART_MSR);
-+ priv->dmsr = msr & QUARK_UART_MSR_DELTA;
-+ return (u8)msr;
-+}
-+
-+static void quark_uart_hal_write(struct x1000_port *priv,
-+ const unsigned char *buf, int tx_size)
-+{
-+ int i;
-+ unsigned int thr;
-+
-+ for (i = 0; i < tx_size;) {
-+ thr = buf[i++];
-+ serial_out(priv, QUARK_UART_THR, thr);
-+ }
-+}
-+
-+static int quark_uart_hal_read(struct x1000_port *priv, unsigned char *buf,
-+ int rx_size)
-+{
-+ int i;
-+ u8 rbr, lsr;
-+ struct uart_port *port = &priv->port;
-+
-+ lsr = serial_in(priv, UART_LSR);
-+ for (i = 0, lsr = serial_in(priv, UART_LSR);
-+ i < rx_size && lsr & (UART_LSR_DR | UART_LSR_BI);
-+ lsr = serial_in(priv, UART_LSR)) {
-+ rbr = serial_in(priv, QUARK_UART_RBR);
-+
-+ if (lsr & UART_LSR_BI) {
-+ port->icount.brk++;
-+ if (uart_handle_break(port))
-+ continue;
-+ }
-+#ifdef SUPPORT_SYSRQ
-+ if (port->sysrq) {
-+ if (uart_handle_sysrq_char(port, rbr))
-+ continue;
-+ }
-+#endif
-+
-+ buf[i++] = rbr;
-+ }
-+ return i;
-+}
-+
-+static unsigned char quark_uart_hal_get_iid(struct x1000_port *priv)
-+{
-+ return serial_in(priv, UART_IIR) &\
-+ (QUARK_UART_IIR_IID | QUARK_UART_IIR_TOI | QUARK_UART_IIR_IP);
-+}
-+
-+static u8 quark_uart_hal_get_line_status(struct x1000_port *priv)
-+{
-+ return serial_in(priv, UART_LSR);
-+}
-+
-+static void quark_uart_hal_set_break(struct x1000_port *priv, int on)
-+{
-+ unsigned int lcr;
-+
-+ lcr = serial_in(priv, UART_LCR);
-+ if (on)
-+ lcr |= QUARK_UART_LCR_SB;
-+ else
-+ lcr &= ~QUARK_UART_LCR_SB;
-+
-+ serial_out(priv, UART_LCR, lcr);
-+}
-+
-+static int push_rx(struct x1000_port *priv, const unsigned char *buf,
-+ int size)
-+{
-+ struct uart_port *port = &priv->port;
-+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-+
-+ tty_insert_flip_string(tty, buf, size);
-+ tty_flip_buffer_push(tty);
-+
-+ return 0;
-+}
-+
-+static int pop_tx_x(struct x1000_port *priv, unsigned char *buf)
-+{
-+ int ret = 0;
-+ struct uart_port *port = &priv->port;
-+
-+ if (port->x_char) {
-+ dev_dbg(priv->port.dev, "%s:X character send %02x (%lu)\n",
-+ __func__, port->x_char, jiffies);
-+ buf[0] = port->x_char;
-+ port->x_char = 0;
-+ ret = 1;
-+ }
-+
-+ return ret;
-+}
-+
-+static int dma_push_rx(struct x1000_port *priv, int size)
-+{
-+ int room;
-+ struct uart_port *port = &priv->port;
-+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-+
-+ room = tty_buffer_request_room(tty, size);
-+
-+ if (room < size)
-+ dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
-+ size - room);
-+ if (!room)
-+ return 0;
-+
-+ tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
-+
-+ port->icount.rx += room;
-+
-+ 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;
-+ struct uart_port *port = &priv->port;
-+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-+ int count;
-+
-+ dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE);
-+ count = dma_push_rx(priv, priv->trigger_level);
-+ if (count)
-+ tty_flip_buffer_push(tty);
-+ async_tx_ack(priv->desc_rx);
-+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_RX_INT |
-+ QUARK_UART_HAL_RX_ERR_INT);
-+}
-+
-+static void quark_dma_tx_complete(void *arg)
-+{
-+ struct x1000_port *priv = arg;
-+ struct uart_port *port = &priv->port;
-+ struct circ_buf *xmit = &port->state->xmit;
-+ struct scatterlist *sg = priv->sg_tx_p;
-+ int i;
-+
-+ 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;
-+ 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;
-+ kfree(priv->sg_tx_p);
-+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_TX_INT);
-+}
-+
-+static int pop_tx(struct x1000_port *priv, int size)
-+{
-+ int count = 0;
-+ struct uart_port *port = &priv->port;
-+ struct circ_buf *xmit = &port->state->xmit;
-+
-+ if (uart_tx_stopped(port) || uart_circ_empty(xmit) || count >= size)
-+ goto pop_tx_end;
-+
-+ do {
-+ int cnt_to_end =
-+ CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-+ int sz = min(size - count, cnt_to_end);
-+ quark_uart_hal_write(priv, &xmit->buf[xmit->tail], sz);
-+ xmit->tail = (xmit->tail + sz) & (UART_XMIT_SIZE - 1);
-+ count += sz;
-+ } while (!uart_circ_empty(xmit) && count < size);
-+
-+pop_tx_end:
-+ dev_dbg(priv->port.dev, "%d characters. Remained %d characters.(%lu)\n",
-+ count, size - count, jiffies);
-+
-+ return count;
-+}
-+
-+static int handle_rx_to(struct x1000_port *priv)
-+{
-+ struct quark_uart_buffer *buf;
-+ int rx_size;
-+ int ret;
-+ if (!priv->start_rx) {
-+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_RX_INT |
-+ QUARK_UART_HAL_RX_ERR_INT);
-+ return 0;
-+ }
-+ buf = &priv->rxbuf;
-+ do {
-+ rx_size = quark_uart_hal_read(priv, buf->buf, buf->size);
-+ ret = push_rx(priv, buf->buf, rx_size);
-+ if (ret)
-+ return 0;
-+ } while (rx_size == buf->size);
-+
-+ return QUARK_UART_HANDLED_RX_INT;
-+}
-+
-+static int handle_rx(struct x1000_port *priv)
-+{
-+ return handle_rx_to(priv);
-+}
-+
-+static int dma_handle_rx(struct x1000_port *priv)
-+{
-+ struct uart_port *port = &priv->port;
-+ struct dma_async_tx_descriptor *desc;
-+ struct scatterlist *sg;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ sg = &priv->sg_rx;
-+
-+ sg_init_table(&priv->sg_rx, 1); /* Initialize SG table */
-+
-+ sg_dma_len(sg) = priv->trigger_level;
-+
-+ sg_set_page(&priv->sg_rx, virt_to_page(priv->rx_buf_virt),
-+ sg_dma_len(sg), (unsigned long)priv->rx_buf_virt &
-+ ~PAGE_MASK);
-+
-+ 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);
-+
-+ if (!desc)
-+ return 0;
-+
-+ priv->desc_rx = desc;
-+ desc->callback = quark_dma_rx_complete;
-+ desc->callback_param = priv;
-+ desc->tx_submit(desc);
-+ dma_async_issue_pending(priv->chan_rx);
-+
-+ return QUARK_UART_HANDLED_RX_INT;
-+}
-+
-+static unsigned int handle_tx(struct x1000_port *priv)
-+{
-+ struct uart_port *port = &priv->port;
-+ struct circ_buf *xmit = &port->state->xmit;
-+ int fifo_size;
-+ int tx_size;
-+ int size;
-+ int tx_empty;
-+
-+ if (!priv->start_tx) {
-+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
-+ __func__, jiffies);
-+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
-+ priv->tx_empty = 1;
-+ return 0;
-+ }
-+
-+ fifo_size = max(priv->fifo_size, 1);
-+ tx_empty = 1;
-+ if (pop_tx_x(priv, xmit->buf)) {
-+ quark_uart_hal_write(priv, xmit->buf, 1);
-+ port->icount.tx++;
-+ tx_empty = 0;
-+ fifo_size--;
-+ }
-+ size = min(xmit->head - xmit->tail, fifo_size);
-+ if (size < 0)
-+ size = fifo_size;
-+
-+ tx_size = pop_tx(priv, size);
-+ if (tx_size > 0) {
-+ port->icount.tx += tx_size;
-+ tx_empty = 0;
-+ }
-+
-+ priv->tx_empty = tx_empty;
-+
-+ if (tx_empty) {
-+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
-+ 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;
-+ struct circ_buf *xmit = &port->state->xmit;
-+ struct scatterlist *sg;
-+ int nent;
-+ int fifo_size;
-+ int tx_empty;
-+ struct dma_async_tx_descriptor *desc;
-+ int num;
-+ int i;
-+ int bytes;
-+ int size;
-+ int rem;
-+
-+ if (!priv->start_tx) {
-+ dev_info(priv->port.dev, "%s:Tx isn't started. (%lu)\n",
-+ __func__, jiffies);
-+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_TX_INT);
-+ priv->tx_empty = 1;
-+ return 0;
-+ }
-+
-+ if (priv->tx_dma_use) {
-+ 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);
-+ priv->tx_empty = 1;
-+ return 0;
-+ }
-+
-+ fifo_size = max(priv->fifo_size, 1);
-+ tx_empty = 1;
-+ if (pop_tx_x(priv, xmit->buf)) {
-+ quark_uart_hal_write(priv, xmit->buf, 1);
-+ port->icount.tx++;
-+ tx_empty = 0;
-+ fifo_size--;
-+ }
-+
-+ 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);
-+ return 0;
-+ }
-+
-+ if (bytes > fifo_size) {
-+ num = bytes / fifo_size + 1;
-+ size = fifo_size;
-+ rem = bytes % fifo_size;
-+ } else {
-+ num = 1;
-+ size = bytes;
-+ rem = bytes;
-+ }
-+
-+ dev_dbg(priv->port.dev, "%s num=%d size=%d rem=%d\n",
-+ __func__, num, size, rem);
-+
-+ priv->tx_dma_use = 1;
-+
-+ priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
-+ if (!priv->sg_tx_p) {
-+ dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__);
-+ return 0;
-+ }
-+
-+ sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
-+ sg = priv->sg_tx_p;
-+
-+ for (i = 0; i < num; i++, sg++) {
-+ if (i == (num - 1))
-+ sg_set_page(sg, virt_to_page(xmit->buf),
-+ rem, fifo_size * i);
-+ else
-+ sg_set_page(sg, virt_to_page(xmit->buf),
-+ size, fifo_size * i);
-+ }
-+
-+ sg = priv->sg_tx_p;
-+ nent = dma_map_sg(port->dev, sg, num, DMA_TO_DEVICE);
-+ if (!nent) {
-+ dev_err(priv->port.dev, "%s:dma_map_sg Failed\n", __func__);
-+ return 0;
-+ }
-+ priv->nent = nent;
-+
-+ for (i = 0; i < nent; i++, sg++) {
-+ sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) +
-+ 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;
-+ else
-+ sg_dma_len(sg) = 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);
-+
-+ return QUARK_UART_HANDLED_TX_INT;
-+}
-+
-+static void quark_uart_err_ir(struct x1000_port *priv, unsigned int lsr)
-+{
-+ struct uart_port *port = &priv->port;
-+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
-+ char *error_msg[5] = {};
-+ int i = 0;
-+
-+ if (lsr & QUARK_UART_LSR_ERR)
-+ error_msg[i++] = "Error data in FIFO\n";
-+
-+ if (lsr & UART_LSR_FE) {
-+ port->icount.frame++;
-+ error_msg[i++] = " Framing Error\n";
-+ }
-+
-+ if (lsr & UART_LSR_PE) {
-+ port->icount.parity++;
-+ error_msg[i++] = " Parity Error\n";
-+ }
-+
-+ if (lsr & UART_LSR_OE) {
-+ port->icount.overrun++;
-+ error_msg[i++] = " Overrun Error\n";
-+ }
-+
-+ if (tty == NULL) {
-+ for (i = 0; error_msg[i] != NULL; i++)
-+ dev_err(&priv->pdev->dev, error_msg[i]);
-+ } else {
-+ tty_kref_put(tty);
-+ }
-+}
-+
-+#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
-+ #define mask_pvm(x) cln_pci_pvm_mask(x)
-+ #define unmask_pvm(x) cln_pci_pvm_unmask(x)
-+#else
-+ #define mask_pvm(x)
-+ #define unmask_pvm(x)
-+#endif
-+
-+static irqreturn_t quark_uart_interrupt(int irq, void *dev_id)
-+{
-+ struct x1000_port *priv = dev_id;
-+ unsigned int handled;
-+ u8 lsr;
-+ int ret = 0;
-+ unsigned char iid;
-+ unsigned long flags;
-+ int next = 1;
-+ u8 msr;
-+
-+ spin_lock_irqsave(&priv->lock, flags);
-+ handled = 0;
-+ while (next) {
-+ iid = quark_uart_hal_get_iid(priv);
-+ if (iid & QUARK_UART_IIR_IP) /* No Interrupt */
-+ break;
-+ switch (iid) {
-+ case QUARK_UART_IID_RLS: /* Receiver Line Status */
-+ lsr = quark_uart_hal_get_line_status(priv);
-+ if (lsr & (QUARK_UART_LSR_ERR | UART_LSR_FE |
-+ UART_LSR_PE | UART_LSR_OE)) {
-+ quark_uart_err_ir(priv, lsr);
-+ ret = QUARK_UART_HANDLED_RX_ERR_INT;
-+ } else {
-+ ret = QUARK_UART_HANDLED_LS_INT;
-+ }
-+ 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);
-+ }
-+ break;
-+ case QUARK_UART_IID_RDR_TO: /* Received Data Ready
-+ (FIFO Timeout) */
-+ ret = handle_rx_to(priv);
-+ break;
-+ case QUARK_UART_IID_THRE: /* Transmitter Holding Register
-+ Empty */
-+ if (priv->use_dma)
-+
-+ ret = dma_handle_tx(priv);
-+ else
-+ ret = handle_tx(priv);
-+ break;
-+ case QUARK_UART_IID_MS: /* Modem Status */
-+ msr = quark_uart_hal_get_modem(priv);
-+ next = 0; /* MS ir prioirty is the lowest. So, MS ir
-+ means final interrupt */
-+ if ((msr & UART_MSR_ANY_DELTA) == 0)
-+ break;
-+ ret |= QUARK_UART_HANDLED_MS_INT;
-+ break;
-+ default: /* Never junp to this label */
-+ dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
-+ iid, jiffies);
-+ ret = -1;
-+ next = 0;
-+ break;
-+ }
-+ handled |= (unsigned int)ret;
-+ }
-+
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+
-+ return IRQ_RETVAL(handled);
-+}
-+
-+/* This function tests whether the transmitter fifo and shifter for the port
-+ described by 'port' is empty. */
-+static unsigned int quark_uart_tx_empty(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ if (priv->tx_empty)
-+ return TIOCSER_TEMT;
-+ else
-+ return 0;
-+}
-+
-+/* Returns the current state of modem control inputs. */
-+static unsigned int quark_uart_get_mctrl(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+ u8 modem;
-+ unsigned int ret = 0;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ modem = quark_uart_hal_get_modem(priv);
-+
-+ if (modem & UART_MSR_DCD)
-+ ret |= TIOCM_CAR;
-+
-+ if (modem & UART_MSR_RI)
-+ ret |= TIOCM_RNG;
-+
-+ if (modem & UART_MSR_DSR)
-+ ret |= TIOCM_DSR;
-+
-+ if (modem & UART_MSR_CTS)
-+ ret |= TIOCM_CTS;
-+
-+ return ret;
-+}
-+
-+static void quark_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
-+{
-+ u32 mcr = 0;
-+ struct x1000_port *priv = container_of(port, struct x1000_port, port);
-+
-+ if (mctrl & TIOCM_DTR)
-+ mcr |= UART_MCR_DTR;
-+ if (mctrl & TIOCM_RTS)
-+ mcr |= UART_MCR_RTS;
-+ if (mctrl & TIOCM_LOOP)
-+ mcr |= UART_MCR_LOOP;
-+
-+ if (priv->mcr & UART_MCR_AFE)
-+ mcr |= UART_MCR_AFE;
-+
-+ if (mctrl)
-+ serial_out(priv, UART_MCR, mcr);
-+}
-+
-+static void quark_uart_stop_tx(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+ priv = container_of(port, struct x1000_port, port);
-+ priv->start_tx = 0;
-+ priv->tx_dma_use = 0;
-+}
-+
-+static void quark_uart_start_tx(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+
-+ if (priv->use_dma) {
-+ if (priv->tx_dma_use) {
-+ dev_dbg(priv->port.dev, "%s : Tx DMA is NOT empty.\n",
-+ __func__);
-+ return;
-+ }
-+ }
-+
-+#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);
-+}
-+
-+static void quark_uart_stop_rx(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ 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);
-+}
-+
-+/* Enable the modem status interrupts. */
-+static void quark_uart_enable_ms(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+ priv = container_of(port, struct x1000_port, port);
-+ quark_uart_hal_enable_interrupt(priv, QUARK_UART_HAL_MS_INT);
-+}
-+
-+/* Control the transmission of a break signal. */
-+static void quark_uart_break_ctl(struct uart_port *port, int ctl)
-+{
-+ struct x1000_port *priv;
-+ unsigned long flags;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ spin_lock_irqsave(&priv->lock, flags);
-+ quark_uart_hal_set_break(priv, ctl);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+/* Grab any interrupt resources and initialise any low level driver state. */
-+static int quark_uart_startup(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+ int ret;
-+ int fifo_size;
-+ int trigger_level;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ priv->tx_empty = 1;
-+
-+ if (port->uartclk)
-+ 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,
-+ QUARK_UART_HAL_STB1);
-+
-+ if (ret)
-+ return ret;
-+
-+ switch (priv->fifo_size) {
-+ case 256:
-+ fifo_size = QUARK_UART_HAL_FIFO256;
-+ break;
-+ case 64:
-+ fifo_size = QUARK_UART_HAL_FIFO64;
-+ break;
-+ case 16:
-+ fifo_size = QUARK_UART_HAL_FIFO16;
-+ break;
-+ case 1:
-+ default:
-+ fifo_size = QUARK_UART_HAL_FIFO_DIS;
-+ break;
-+ }
-+
-+ switch (priv->trigger) {
-+ case QUARK_UART_HAL_TRIGGER1:
-+ trigger_level = 1;
-+ break;
-+ case QUARK_UART_HAL_TRIGGER_L:
-+ trigger_level = priv->fifo_size / 4;
-+ break;
-+ case QUARK_UART_HAL_TRIGGER_M:
-+ trigger_level = priv->fifo_size / 2;
-+ break;
-+ case QUARK_UART_HAL_TRIGGER_H:
-+ default:
-+ trigger_level = priv->fifo_size - (priv->fifo_size / 8);
-+ break;
-+ }
-+
-+ 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;
-+}
-+
-+static void quark_uart_shutdown(struct uart_port *port)
-+{
-+ 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);
-+ 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,
-+ QUARK_UART_HAL_FIFO_DIS, QUARK_UART_HAL_TRIGGER1);
-+ 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
-+ *bits. Update read_status_mask and ignore_status_mask to indicate
-+ *the types of events we are interested in receiving. */
-+static void quark_uart_set_termios(struct uart_port *port,
-+ struct ktermios *termios, struct ktermios *old)
-+{
-+ int rtn;
-+ unsigned int baud, parity, bits, stb;
-+ struct x1000_port *priv;
-+ unsigned long flags;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ switch (termios->c_cflag & CSIZE) {
-+ case CS5:
-+ bits = QUARK_UART_HAL_5BIT;
-+ break;
-+ case CS6:
-+ bits = QUARK_UART_HAL_6BIT;
-+ break;
-+ case CS7:
-+ bits = QUARK_UART_HAL_7BIT;
-+ break;
-+ default: /* CS8 */
-+ bits = QUARK_UART_HAL_8BIT;
-+ break;
-+ }
-+ if (termios->c_cflag & CSTOPB)
-+ stb = QUARK_UART_HAL_STB2;
-+ else
-+ stb = QUARK_UART_HAL_STB1;
-+
-+ if (termios->c_cflag & PARENB) {
-+ if (termios->c_cflag & PARODD)
-+ parity = QUARK_UART_HAL_PARITY_ODD;
-+ else
-+ parity = QUARK_UART_HAL_PARITY_EVEN;
-+
-+ } else
-+ parity = QUARK_UART_HAL_PARITY_NONE;
-+
-+ /* Only UART0 has auto hardware flow function */
-+ if ((termios->c_cflag & CRTSCTS) && (priv->fifo_size == 256))
-+ priv->mcr |= UART_MCR_AFE;
-+ else
-+ priv->mcr &= ~UART_MCR_AFE;
-+
-+ 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);
-+
-+ uart_update_timeout(port, termios->c_cflag, baud);
-+ rtn = quark_uart_hal_set_line(priv, baud, parity, bits, stb);
-+ if (rtn)
-+ goto out;
-+
-+ quark_uart_set_mctrl(&priv->port, priv->port.mctrl);
-+ /* Don't rewrite B0 */
-+ if (tty_termios_baud_rate(termios))
-+ tty_termios_encode_baud_rate(termios, baud, baud);
-+
-+out:
-+ spin_unlock(&port->lock);
-+ spin_unlock_irqrestore(&priv->lock, flags);
-+}
-+
-+static const char *quark_uart_type(struct uart_port *port)
-+{
-+ return KBUILD_MODNAME;
-+}
-+
-+static void quark_uart_release_port(struct uart_port *port)
-+{
-+ struct x1000_port *priv;
-+
-+ priv = container_of(port, struct x1000_port, port);
-+ pci_iounmap(priv->pdev, priv->membase);
-+ pci_release_regions(priv->pdev);
-+}
-+
-+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;
-+}
-+
-+static void quark_uart_config_port(struct uart_port *port, int type)
-+{
-+ 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;
-+ quark_uart_request_port(port);
-+ }
-+}
-+
-+static int quark_uart_verify_port(struct uart_port *port,
-+ 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;
-+ 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 (!priv->use_dma)
-+ quark_request_dma(port);
-+ priv->use_dma = 1;
-+ }
-+
-+ return 0;
-+}
-+
-+#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_QUARK_UART_CONSOLE)
-+/*
-+ * Wait for transmitter & holding register to empty
-+ */
-+static void wait_for_xmitr(struct x1000_port *up, int bits)
-+{
-+ unsigned int status, tmout = 10000;
-+
-+ /* Wait up to 10ms for the character(s) to be sent. */
-+ for (;;) {
-+ status = serial_in(up, UART_LSR);
-+
-+ if ((status & bits) == bits)
-+ break;
-+ if (--tmout == 0)
-+ break;
-+ udelay(1);
-+ }
-+
-+ /* Wait up to 1s for flow control if necessary */
-+ if (up->port.flags & UPF_CONS_FLOW) {
-+ unsigned int tmout;
-+ for (tmout = 1000000; tmout; tmout--) {
-+ unsigned int msr = serial_in(up, UART_MSR);
-+ if (msr & UART_MSR_CTS)
-+ break;
-+ udelay(1);
-+ touch_nmi_watchdog();
-+ }
-+ }
-+}
-+#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_QUARK_UART_CONSOLE */
-+
-+#ifdef CONFIG_CONSOLE_POLL
-+/*
-+ * Console polling routines for communicate via uart while
-+ * in an interrupt or debug context.
-+ */
-+static int quark_uart_get_poll_char(struct uart_port *port)
-+{
-+ struct x1000_port *priv =
-+ container_of(port, struct x1000_port, port);
-+ u8 lsr = serial_in(priv, UART_LSR);
-+
-+ if (!(lsr & UART_LSR_DR))
-+ return NO_POLL_CHAR;
-+
-+ return serial_in(priv, QUARK_UART_RBR);
-+}
-+
-+
-+static void quark_uart_put_poll_char(struct uart_port *port,
-+ unsigned char c)
-+{
-+ unsigned int ier;
-+ struct x1000_port *priv =
-+ container_of(port, struct x1000_port, port);
-+
-+ /*
-+ * First save the IER then disable the interrupts
-+ */
-+ ier = serial_in(priv, UART_IER);
-+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT);
-+
-+ wait_for_xmitr(priv, UART_LSR_THRE);
-+ /*
-+ * Send the character out.
-+ * If a LF, also do CR...
-+ */
-+ serial_out(priv, QUARK_UART_THR, c);
-+ if (c == 10) {
-+ wait_for_xmitr(priv, UART_LSR_THRE);
-+ serial_out(priv, QUARK_UART_THR, 13);
-+ }
-+
-+ /*
-+ * Finally, wait for transmitter to become empty
-+ * and restore the IER
-+ */
-+ wait_for_xmitr(priv, BOTH_EMPTY);
-+ serial_out(priv, UART_IER, ier);
-+}
-+#endif /* CONFIG_CONSOLE_POLL */
-+
-+static struct uart_ops quark_uart_ops = {
-+ .tx_empty = quark_uart_tx_empty,
-+ .set_mctrl = quark_uart_set_mctrl,
-+ .get_mctrl = quark_uart_get_mctrl,
-+ .stop_tx = quark_uart_stop_tx,
-+ .start_tx = quark_uart_start_tx,
-+ .stop_rx = quark_uart_stop_rx,
-+ .enable_ms = quark_uart_enable_ms,
-+ .break_ctl = quark_uart_break_ctl,
-+ .startup = quark_uart_startup,
-+ .shutdown = quark_uart_shutdown,
-+ .set_termios = quark_uart_set_termios,
-+/* .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,
-+ .request_port = quark_uart_request_port,
-+ .config_port = quark_uart_config_port,
-+ .verify_port = quark_uart_verify_port,
-+#ifdef CONFIG_CONSOLE_POLL
-+ .poll_get_char = quark_uart_get_poll_char,
-+ .poll_put_char = quark_uart_put_poll_char,
-+#endif
-+};
-+
-+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
-+
-+static void quark_console_putchar(struct uart_port *port, int ch)
-+{
-+ struct x1000_port *priv =
-+ container_of(port, struct x1000_port, port);
-+
-+ wait_for_xmitr(priv, UART_LSR_THRE);
-+ serial_out(priv, QUARK_UART_THR, ch);
-+}
-+
-+/*
-+ * Print a string to the serial port trying not to disturb
-+ * any possible real use of the port...
-+ *
-+ * The console_lock must be held when we get here.
-+ */
-+static void
-+quark_console_write(struct console *co, const char *s, unsigned int count)
-+{
-+ struct x1000_port *priv;
-+ unsigned long flags;
-+ int priv_locked = 1;
-+ int port_locked = 1;
-+ u8 ier;
-+
-+ priv = quark_uart_ports[co->index];
-+
-+ touch_nmi_watchdog();
-+
-+ local_irq_save(flags);
-+ 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 */
-+ port_locked = 0;
-+ } else if (oops_in_progress) {
-+ priv_locked = spin_trylock(&priv->lock);
-+ port_locked = spin_trylock(&priv->port.lock);
-+ } else {
-+ spin_lock(&priv->lock);
-+ spin_lock(&priv->port.lock);
-+ }
-+
-+ /*
-+ * First save the IER then disable the interrupts
-+ */
-+ ier = serial_in(priv, UART_IER);
-+
-+ quark_uart_hal_disable_interrupt(priv, QUARK_UART_HAL_ALL_INT);
-+
-+ uart_console_write(&priv->port, s, count, quark_console_putchar);
-+
-+ /*
-+ * Finally, wait for transmitter to become empty
-+ * and restore the IER
-+ */
-+ wait_for_xmitr(priv, BOTH_EMPTY);
-+ serial_out(priv, UART_IER, ier);
-+
-+ if (port_locked)
-+ spin_unlock(&priv->port.lock);
-+ if (priv_locked)
-+ spin_unlock(&priv->lock);
-+ local_irq_restore(flags);
-+}
-+
-+static int __init quark_console_setup(struct console *co, char *options)
-+{
-+ struct uart_port *port;
-+ int baud = default_baud;
-+ int bits = 8;
-+ int parity = 'n';
-+ int flow = 'n';
-+
-+ /*
-+ * Check whether an invalid uart number has been specified, and
-+ * if so, search for the first available port that does have
-+ * console support.
-+ */
-+ if (co->index >= QUARK_UART_NR)
-+ co->index = 0;
-+ port = &quark_uart_ports[co->index]->port;
-+
-+ if (!port || !port->membase)
-+ return -ENODEV;
-+
-+ port->uartclk = quark_uart_get_uartclk();
-+
-+ if (options)
-+ uart_parse_options(options, &baud, &parity, &bits, &flow);
-+
-+ 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,
-+ .device = uart_console_device,
-+ .setup = quark_console_setup,
-+ .flags = CON_PRINTBUFFER | CON_ANYTIME,
-+ .index = -1,
-+ .data = &quark_uart_driver,
-+};
-+
-+#define QUARK_CONSOLE (&quark_console)
-+#else
-+#define QUARK_CONSOLE NULL
-+#endif /* CONFIG_SERIAL_QUARK_UART_CONSOLE */
-+
-+static struct uart_driver quark_uart_driver = {
-+ .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 struct x1000_port *quark_uart_init_port(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
-+{
-+ struct x1000_port *priv;
-+ int ret, len;
-+ 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",
-+ 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;
-+
-+ rxbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
-+ if (!rxbuf)
-+ goto init_port_free_txbuf;
-+
-+ pci_set_master(pdev);
-+
-+ spin_lock_init(&priv->lock);
-+
-+ priv->mapbase = pci_resource_start(pdev, 0);
-+ len = pci_resource_len(pdev, 0);
-+ priv->membase = ioremap_nocache(priv->mapbase, len);
-+ if(priv->membase == NULL){
-+ ret = -ENODEV;
-+ goto init_port_free_txbuf;
-+ }
-+
-+ priv->pdev = pdev;
-+ priv->tx_empty = 1;
-+ priv->rxbuf.buf = rxbuf;
-+ priv->rxbuf.size = PAGE_SIZE;
-+ priv->fifo_size = QUARK_UART_FIFO_LEN;
-+ priv->uartclk = quark_uart_get_uartclk();
-+ priv->port_type = PORT_MAX_8250 + 1; /* BOD what does this do ? TBD*/
-+ priv->port.dev = &pdev->dev;
-+ priv->port.membase = priv->membase;
-+ priv->port.mapbase = priv->mapbase;
-+ priv->port.irq = pdev->irq;
-+ priv->port.iotype = UPIO_MEM;
-+ 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;
-+
-+ spin_lock_init(&priv->port.lock);
-+ pci_set_drvdata(pdev, priv);
-+ priv->trigger_level = 1;
-+ priv->fcr = 0;
-+
-+ 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)
-+ goto init_port_hal_free;
-+
-+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
-+ quark_uart_ports[board->line_no] = priv;
-+#endif
-+ ret = uart_add_one_port(&quark_uart_driver, &priv->port);
-+
-+ if (ret < 0)
-+ 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
-+
-+ 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_txbuf:
-+ kfree(priv);
-+init_port_alloc_err:
-+
-+ return NULL;
-+}
-+
-+static void quark_uart_exit_port(struct x1000_port *priv)
-+{
-+
-+#ifdef CONFIG_DEBUG_FS
-+ if (priv->debugfs)
-+ debugfs_remove(priv->debugfs);
-+#endif
-+ free_irq(priv->port.irq, priv);
-+ uart_remove_one_port(&quark_uart_driver, &priv->port);
-+ pci_set_drvdata(priv->pdev, NULL);
-+ free_page((unsigned long)priv->rxbuf.buf);
-+}
-+
-+static void quark_uart_pci_remove(struct pci_dev *pdev)
-+{
-+ struct x1000_port *priv = pci_get_drvdata(pdev);
-+
-+ pci_disable_msi(pdev);
-+
-+#ifdef CONFIG_SERIAL_QUARK_UART_CONSOLE
-+ quark_uart_ports[priv->port.line] = NULL;
-+#endif
-+ quark_uart_exit_port(priv);
-+ pci_disable_device(pdev);
-+ kfree(priv);
-+ return;
-+}
-+#ifdef CONFIG_PM
-+static int quark_uart_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-+{
-+ struct x1000_port *priv = pci_get_drvdata(pdev);
-+
-+ uart_suspend_port(&quark_uart_driver, &priv->port);
-+
-+ pci_save_state(pdev);
-+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
-+ return 0;
-+}
-+
-+static int quark_uart_pci_resume(struct pci_dev *pdev)
-+{
-+ struct x1000_port *priv = pci_get_drvdata(pdev);
-+ int ret;
-+
-+ pci_set_power_state(pdev, PCI_D0);
-+ pci_restore_state(pdev);
-+
-+ ret = pci_enable_device(pdev);
-+ if (ret) {
-+ dev_err(&pdev->dev,
-+ "%s-pci_enable_device failed(ret=%d) ", __func__, ret);
-+ return ret;
-+ }
-+
-+ uart_resume_port(&quark_uart_driver, &priv->port);
-+
-+ return 0;
-+}
-+#else
-+#define quark_uart_pci_suspend NULL
-+#define quark_uart_pci_resume NULL
-+#endif
-+
-+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)},
-+ { 0 }
-+};
-+
-+static int quark_uart_pci_probe(struct pci_dev *pdev,
-+ const struct pci_device_id *id)
-+{
-+ int ret;
-+ struct x1000_port *priv;
-+
-+ ret = pci_enable_device(pdev);
-+ if (ret < 0)
-+ goto probe_error;
-+
-+ priv = quark_uart_init_port(pdev, id);
-+ if (!priv) {
-+ ret = -EBUSY;
-+ goto probe_disable_device;
-+ }
-+ pci_set_drvdata(pdev, priv);
-+
-+ return ret;
-+
-+probe_disable_device:
-+ pci_disable_msi(pdev);
-+ pci_disable_device(pdev);
-+probe_error:
-+ return ret;
-+}
-+
-+static struct pci_driver quark_uart_pci_driver = {
-+ .name = "quark_uart",
-+ .id_table = quark_uart_pci_ids,
-+ .probe = quark_uart_pci_probe,
-+ .remove = quark_uart_pci_remove,
-+ .suspend = quark_uart_pci_suspend,
-+ .resume = quark_uart_pci_resume,
-+};
-+
-+static int __init quark_uart_module_init(void)
-+{
-+ int ret;
-+
-+ /* register as UART driver */
-+ ret = uart_register_driver(&quark_uart_driver);
-+ if (ret < 0)
-+ return ret;
-+
-+ /* register as PCI driver */
-+ ret = pci_register_driver(&quark_uart_pci_driver);
-+ if (ret < 0)
-+ uart_unregister_driver(&quark_uart_driver);
-+
-+ return ret;
-+}
-+module_init(quark_uart_module_init);
-+
-+static void __exit quark_uart_module_exit(void)
-+{
-+ pci_unregister_driver(&quark_uart_pci_driver);
-+ uart_unregister_driver(&quark_uart_driver);
-+}
-+module_exit(quark_uart_module_exit);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("Intel QUARK X1000 UART PCI Driver");
-+module_param(default_baud, uint, S_IRUGO);
-+MODULE_PARM_DESC(default_baud,
-+ "Default BAUD for initial driver state and console (default 115200)");
-diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
-index da9fde8..6b20fd6 100644
---- a/drivers/tty/tty_io.c
-+++ b/drivers/tty/tty_io.c
-@@ -2906,9 +2906,9 @@ void do_SAK(struct tty_struct *tty)
-
- EXPORT_SYMBOL(do_SAK);
-
--static int dev_match_devt(struct device *dev, void *data)
-+static int dev_match_devt(struct device *dev, const void *data)
- {
-- dev_t *devt = data;
-+ const dev_t *devt = data;
- return dev->devt == *devt;
- }
-
-diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
-index c578229..78f1be2 100644
---- a/drivers/tty/tty_ldisc.c
-+++ b/drivers/tty/tty_ldisc.c
-@@ -934,17 +934,17 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
- * race with the set_ldisc code path.
- */
-
-- tty_lock_pair(tty, o_tty);
- tty_ldisc_halt(tty);
-- tty_ldisc_flush_works(tty);
-- if (o_tty) {
-+ if (o_tty)
- tty_ldisc_halt(o_tty);
-+
-+ tty_ldisc_flush_works(tty);
-+ if (o_tty)
- tty_ldisc_flush_works(o_tty);
-- }
-
-+ tty_lock_pair(tty, o_tty);
- /* This will need doing differently if we need to lock */
- tty_ldisc_kill(tty);
--
- if (o_tty)
- tty_ldisc_kill(o_tty);
-
-diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
-index 14625fd..21222a8 100644
---- a/drivers/usb/gadget/Kconfig
-+++ b/drivers/usb/gadget/Kconfig
-@@ -439,7 +439,7 @@ config USB_GOKU
- gadget drivers to also be dynamically linked.
-
- config USB_EG20T
-- tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
-+ tristate "Intel CLN/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
- depends on PCI
- help
- This is a USB device driver for EG20T PCH.
-@@ -459,7 +459,8 @@ config USB_EG20T
- ML7831 is for general purpose use.
- ML7213/ML7831 is companion chip for Intel Atom E6xx series.
- ML7213/ML7831 is completely compatible for Intel EG20T PCH.
--
-+
-+ This driver can be used with Intel's Clanton SOC platform
- #
- # LAST -- dummy/emulated controller
- #
-diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
-index 6490c00..848c502 100644
---- a/drivers/usb/gadget/pch_udc.c
-+++ b/drivers/usb/gadget/pch_udc.c
-@@ -6,6 +6,7 @@
- * the Free Software Foundation; version 2 of the License.
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-+#include <asm/cln.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/pci.h>
-@@ -18,6 +19,10 @@
- #include <linux/gpio.h>
- #include <linux/irq.h>
-
-+static unsigned int enable_msi = 1;
-+module_param(enable_msi, uint, S_IRUGO | S_IWUSR);
-+MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
-+
- /* GPIO port for VBUS detecting */
- static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
-
-@@ -343,6 +348,7 @@ struct pch_vbus_gpio_data {
- * @setup_data: Received setup data
- * @phys_addr: of device memory
- * @base_addr: for mapped device memory
-+ * @bar: Indicates which PCI BAR for USB regs
- * @irq: IRQ line for the device
- * @cfg_data: current cfg, intf, and alt in use
- * @vbus_gpio: GPIO informaton for detecting VBUS
-@@ -371,13 +377,16 @@ struct pch_udc_dev {
- struct usb_ctrlrequest setup_data;
- unsigned long phys_addr;
- void __iomem *base_addr;
-+ unsigned bar;
- unsigned irq;
- struct pch_udc_cfg_data cfg_data;
- struct pch_vbus_gpio_data vbus_gpio;
- };
-
--#define PCH_UDC_PCI_BAR 1
-+#define PCH_UDC_PCI_BAR_CLANTON 0
-+#define PCH_UDC_PCI_BAR_EG20T 1
- #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808
-+#define PCI_DEVICE_ID_INTEL_CLANTON_UDC 0x0939
- #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)
- {
- struct pch_udc_dev *dev = (struct pch_udc_dev *) pdev;
- u32 dev_intr, ep_intr;
-- int i;
--
-- dev_intr = pch_udc_read_device_interrupts(dev);
-- ep_intr = pch_udc_read_ep_interrupts(dev);
--
-- /* For a hot plug, this find that the controller is hung up. */
-- if (dev_intr == ep_intr)
-- if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
-- dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
-- /* The controller is reset */
-- pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
-- return IRQ_HANDLED;
-+ int i, events = 0;
-+
-+ mask_pvm(dev->pdev);
-+ do {
-+ events = 0;
-+ dev_intr = pch_udc_read_device_interrupts(dev);
-+ ep_intr = pch_udc_read_ep_interrupts(dev);
-+
-+ /* For a hot plug, this find that the controller is hung up. */
-+ if (dev_intr == ep_intr)
-+ if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
-+ dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
-+ /* The controller is reset */
-+ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
-+ unmask_pvm(dev->pdev);
-+ return IRQ_HANDLED;
-+ }
-+ if (dev_intr){
-+ /* Clear device interrupts */
-+ pch_udc_write_device_interrupts(dev, dev_intr);
-+ events = 1;
- }
-- if (dev_intr)
-- /* Clear device interrupts */
-- pch_udc_write_device_interrupts(dev, dev_intr);
-- if (ep_intr)
-- /* Clear ep interrupts */
-- pch_udc_write_ep_interrupts(dev, ep_intr);
-- if (!dev_intr && !ep_intr)
-- return IRQ_NONE;
-- spin_lock(&dev->lock);
-- if (dev_intr)
-- pch_udc_dev_isr(dev, dev_intr);
-- if (ep_intr) {
-- pch_udc_read_all_epstatus(dev, ep_intr);
-- /* Process Control In interrupts, if present */
-- if (ep_intr & UDC_EPINT_IN_EP0) {
-- pch_udc_svc_control_in(dev);
-- pch_udc_postsvc_epinters(dev, 0);
-+ if (ep_intr){
-+ /* Clear ep interrupts */
-+ pch_udc_write_ep_interrupts(dev, ep_intr);
-+ events = 1;
- }
-- /* Process Control Out interrupts, if present */
-- if (ep_intr & UDC_EPINT_OUT_EP0)
-- pch_udc_svc_control_out(dev);
-- /* Process data in end point interrupts */
-- for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
-- if (ep_intr & (1 << i)) {
-- pch_udc_svc_data_in(dev, i);
-- pch_udc_postsvc_epinters(dev, i);
-+ if (!dev_intr && !ep_intr){
-+ unmask_pvm(dev->pdev);
-+ return IRQ_NONE;
-+ }
-+ spin_lock(&dev->lock);
-+ if (dev_intr){
-+ pch_udc_dev_isr(dev, dev_intr);
-+ }
-+ if (ep_intr) {
-+ pch_udc_read_all_epstatus(dev, ep_intr);
-+ /* Process Control In interrupts, if present */
-+ 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);
-+ /* Process data in end point interrupts */
-+ for (i = 1; i < PCH_UDC_USED_EP_NUM; i++) {
-+ if (ep_intr & (1 << i)) {
-+ 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);
-+ i++)
-+ if (ep_intr & (1 << i))
-+ pch_udc_svc_data_out(dev,
-+ i - UDC_EPINT_OUT_SHIFT);
- }
-- /* Process data out end point interrupts */
-- for (i = UDC_EPINT_OUT_SHIFT + 1; i < (UDC_EPINT_OUT_SHIFT +
-- PCH_UDC_USED_EP_NUM); i++)
-- if (ep_intr & (1 << i))
-- pch_udc_svc_data_out(dev, i -
-- UDC_EPINT_OUT_SHIFT);
-- }
-- spin_unlock(&dev->lock);
-+ spin_unlock(&dev->lock);
-+ }while(events == 1);
-+ unmask_pvm(dev->pdev);
-+
- return IRQ_HANDLED;
- }
-
-@@ -3108,7 +3132,7 @@ static void pch_udc_remove(struct pci_dev *pdev)
- iounmap(dev->base_addr);
- if (dev->mem_region)
- release_mem_region(dev->phys_addr,
-- pci_resource_len(pdev, PCH_UDC_PCI_BAR));
-+ pci_resource_len(pdev, dev->bar));
- if (dev->active)
- pci_disable_device(pdev);
- if (dev->registered)
-@@ -3184,9 +3208,16 @@ static int pch_udc_probe(struct pci_dev *pdev,
- dev->active = 1;
- pci_set_drvdata(pdev, dev);
-
-+ /* Determine BAR based on PCI ID */
-+ if(id->device == PCI_DEVICE_ID_INTEL_CLANTON_UDC){
-+ dev->bar = PCH_UDC_PCI_BAR_CLANTON;
-+ }else {
-+ dev->bar = PCH_UDC_PCI_BAR_EG20T;
-+ }
-+
- /* PCI resource allocation */
-- resource = pci_resource_start(pdev, 1);
-- len = pci_resource_len(pdev, 1);
-+ resource = pci_resource_start(pdev, dev->bar);
-+ len = pci_resource_len(pdev, dev->bar);
-
- 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,
- retval = -ENODEV;
- goto finished;
- }
-+
-+ pci_set_master(pdev);
-+ if (enable_msi == 1){
-+ pci_enable_msi(pdev);
-+ }
-+
- 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,
- dev->irq = pdev->irq;
- dev->irq_registered = 1;
-
-- pci_set_master(pdev);
-+
- pci_try_set_mwi(pdev);
-
- /* device struct setup */
-@@ -3261,6 +3298,11 @@ finished:
-
- static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
- {
-+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CLANTON_UDC),
-+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
-+ .class_mask = 0xffffffff,
-+ },
-+ {
- PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),
- .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
- .class_mask = 0xffffffff,
-diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
-index 44752f5..e02a4c9 100644
---- a/drivers/usb/gadget/serial.c
-+++ b/drivers/usb/gadget/serial.c
-@@ -127,6 +127,15 @@ static unsigned n_ports = 1;
- module_param(n_ports, uint, 0);
- MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
-
-+static __u16 vendor = GS_VENDOR_ID;
-+module_param(vendor, ushort, 0);
-+MODULE_PARM_DESC(vendor, "User specified vendor ID (default="
-+ __MODULE_STRING(GS_VENDOR_ID)")");
-+
-+static __u16 product = 0;
-+module_param(product, ushort, 0);
-+MODULE_PARM_DESC(product, "User specified product ID");
-+
- /*-------------------------------------------------------------------------*/
-
- static int __init serial_bind_config(struct usb_configuration *c)
-@@ -172,6 +181,14 @@ static int __init gs_bind(struct usb_composite_dev *cdev)
- status = strings_dev[STRING_DESCRIPTION_IDX].id;
- serial_config_driver.iConfiguration = status;
-
-+ /* Allow command line over-ride to set specific vendor/device id */
-+ if (vendor != GS_VENDOR_ID)
-+ device_desc.idVendor = cpu_to_le16(vendor);
-+ if (product != 0)
-+ device_desc.idProduct = cpu_to_le16(product);
-+ pr_info("g_serial: Vendor 0x%04x Product 0x%04x\n",
-+ device_desc.idVendor, device_desc.idProduct);
-+
- if (gadget_is_otg(cdev->gadget)) {
- serial_config_driver.descriptors = otg_desc;
- serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-@@ -201,6 +218,7 @@ static __refdata struct usb_composite_driver gserial_driver = {
- .bind = gs_bind,
- };
-
-+static int bCfgVal;
- static int __init init(void)
- {
- /* We *could* export two configs; that'd be much cleaner...
-@@ -208,19 +226,19 @@ static int __init init(void)
- */
- if (use_acm) {
- serial_config_driver.label = "CDC ACM config";
-- serial_config_driver.bConfigurationValue = 2;
-+ serial_config_driver.bConfigurationValue = ++bCfgVal;
- device_desc.bDeviceClass = USB_CLASS_COMM;
- device_desc.idProduct =
- cpu_to_le16(GS_CDC_PRODUCT_ID);
- } else if (use_obex) {
- serial_config_driver.label = "CDC OBEX config";
-- serial_config_driver.bConfigurationValue = 3;
-+ serial_config_driver.bConfigurationValue = ++bCfgVal;
- device_desc.bDeviceClass = USB_CLASS_COMM;
- device_desc.idProduct =
- cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
- } else {
- serial_config_driver.label = "Generic Serial config";
-- serial_config_driver.bConfigurationValue = 1;
-+ serial_config_driver.bConfigurationValue = ++bCfgVal;
- device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
- device_desc.idProduct =
- cpu_to_le16(GS_PRODUCT_ID);
-diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
-index 170b939..e34f67c 100644
---- a/drivers/usb/host/ehci-pci.c
-+++ b/drivers/usb/host/ehci-pci.c
-@@ -50,6 +50,10 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
- if (!retval)
- ehci_dbg(ehci, "MWI active\n");
-
-+ /* Reset the threshold limit */
-+ if(unlikely(usb_is_intel_cln(pdev)))
-+ usb_set_cln_bulk_thresh(pdev);
-+
- return 0;
- }
-
-diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
-index 4c338ec..401780b 100644
---- a/drivers/usb/host/pci-quirks.c
-+++ b/drivers/usb/host/pci-quirks.c
-@@ -722,6 +722,48 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
- return -ETIMEDOUT;
- }
-
-+#define PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC 0x0939
-+bool usb_is_intel_cln(struct pci_dev *pdev)
-+{
-+ return pdev->vendor == PCI_VENDOR_ID_INTEL &&
-+ pdev->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_SOC;
-+
-+}
-+EXPORT_SYMBOL_GPL(usb_is_intel_cln);
-+
-+#define EHCI_INSNREG01 0x84
-+#define EHCI_INSNREG01_THRESH 0x007F007F /* Threshold value */
-+void usb_set_cln_bulk_thresh(struct pci_dev *pdev)
-+{
-+ void __iomem *base, *op_reg_base;
-+ u8 cap_length;
-+ u32 val;
-+
-+ if (!mmio_resource_enabled(pdev, 0))
-+ return;
-+
-+ base = pci_ioremap_bar(pdev, 0);
-+ if (base == NULL)
-+ return;
-+
-+ cap_length = readb(base);
-+ op_reg_base = base + cap_length;
-+
-+ val = readl(op_reg_base + EHCI_INSNREG01);
-+ dev_printk(KERN_INFO, &pdev->dev, "INSNREG01 is 0x%08x\n", val);
-+
-+ val = EHCI_INSNREG01_THRESH;
-+
-+ writel(val, op_reg_base + EHCI_INSNREG01);
-+
-+ val = readl(op_reg_base + EHCI_INSNREG01);
-+ dev_printk(KERN_INFO, &pdev->dev, "INSNREG01 is 0x%08x\n", val);
-+
-+ iounmap(base);
-+
-+}
-+EXPORT_SYMBOL_GPL(usb_set_cln_bulk_thresh);
-+
- #define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31
- #define PCI_DEVICE_ID_INTEL_LYNX_POINT_LP_XHCI 0x9C31
-
-diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
-index 7f69a39..3bca8f7 100644
---- a/drivers/usb/host/pci-quirks.h
-+++ b/drivers/usb/host/pci-quirks.h
-@@ -9,6 +9,8 @@ void usb_amd_dev_put(void);
- void usb_amd_quirk_pll_disable(void);
- void usb_amd_quirk_pll_enable(void);
- bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
-+bool usb_is_intel_cln(struct pci_dev *pdev);
-+void usb_set_cln_bulk_thresh(struct pci_dev *pdev);
- void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
- void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
- #else
-diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
-index 4d688c7..3eca6ce 100644
---- a/drivers/uwb/lc-rc.c
-+++ b/drivers/uwb/lc-rc.c
-@@ -40,9 +40,9 @@
-
- #include "uwb-internal.h"
-
--static int uwb_rc_index_match(struct device *dev, void *data)
-+static int uwb_rc_index_match(struct device *dev, const void *data)
- {
-- int *index = data;
-+ const int *index = data;
- struct uwb_rc *rc = dev_get_drvdata(dev);
-
- if (rc->index == *index)
-@@ -334,9 +334,9 @@ void uwb_rc_rm(struct uwb_rc *rc)
- }
- EXPORT_SYMBOL_GPL(uwb_rc_rm);
-
--static int find_rc_try_get(struct device *dev, void *data)
-+static int find_rc_try_get(struct device *dev, const void *data)
- {
-- struct uwb_rc *target_rc = data;
-+ const struct uwb_rc *target_rc = data;
- struct uwb_rc *rc = dev_get_drvdata(dev);
-
- if (rc == NULL) {
-@@ -386,9 +386,9 @@ static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
- return rc;
- }
-
--static int find_rc_grandpa(struct device *dev, void *data)
-+static int find_rc_grandpa(struct device *dev, const void *data)
- {
-- struct device *grandpa_dev = data;
-+ const struct device *grandpa_dev = data;
- struct uwb_rc *rc = dev_get_drvdata(dev);
-
- if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
-@@ -419,7 +419,7 @@ struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
- struct device *dev;
- struct uwb_rc *rc = NULL;
-
-- dev = class_find_device(&uwb_rc_class, NULL, (void *)grandpa_dev,
-+ dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
- find_rc_grandpa);
- if (dev)
- rc = dev_get_drvdata(dev);
-@@ -432,9 +432,9 @@ EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
- *
- * @returns the pointer to the radio controller, properly referenced
- */
--static int find_rc_dev(struct device *dev, void *data)
-+static int find_rc_dev(struct device *dev, const void *data)
- {
-- struct uwb_dev_addr *addr = data;
-+ const struct uwb_dev_addr *addr = data;
- struct uwb_rc *rc = dev_get_drvdata(dev);
-
- if (rc == NULL) {
-@@ -453,8 +453,7 @@ struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
- struct device *dev;
- struct uwb_rc *rc = NULL;
-
-- dev = class_find_device(&uwb_rc_class, NULL, (void *)addr,
-- find_rc_dev);
-+ dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
- if (dev)
- rc = dev_get_drvdata(dev);
-
-diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
-index 20ca766..8265ccc 100644
---- a/include/asm-generic/gpio.h
-+++ b/include/asm-generic/gpio.h
-@@ -65,6 +65,7 @@ struct device_node;
- * @direction_output: configures signal "offset" as output, or returns error
- * @set_debounce: optional hook for setting debounce time for specified gpio in
- * interrupt triggered gpio chips
-+ * @set_drive: optional hook for setting the drive signal for "offset"
- * @set: assigns output value for signal "offset"
- * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
- * implementation may not sleep
-@@ -113,6 +114,8 @@ struct gpio_chip {
- unsigned offset, int value);
- int (*set_debounce)(struct gpio_chip *chip,
- unsigned offset, unsigned debounce);
-+ int (*set_drive)(struct gpio_chip *chip,
-+ unsigned offset, unsigned mode);
-
- void (*set)(struct gpio_chip *chip,
- unsigned offset, int value);
-@@ -172,6 +175,7 @@ extern int gpio_direction_input(unsigned gpio);
- extern int gpio_direction_output(unsigned gpio, int value);
-
- extern int gpio_set_debounce(unsigned gpio, unsigned debounce);
-+extern int gpio_set_drive(unsigned gpio, unsigned mode);
-
- extern int gpio_get_value_cansleep(unsigned gpio);
- extern void gpio_set_value_cansleep(unsigned gpio, int value);
-diff --git a/include/linux/device.h b/include/linux/device.h
-index 43dcda9..13de5ee 100644
---- a/include/linux/device.h
-+++ b/include/linux/device.h
-@@ -395,8 +395,8 @@ extern int class_for_each_device(struct class *class, struct device *start,
- void *data,
- int (*fn)(struct device *dev, void *data));
- extern struct device *class_find_device(struct class *class,
-- struct device *start, void *data,
-- int (*match)(struct device *, void *));
-+ struct device *start, const void *data,
-+ int (*match)(struct device *, const void *));
-
- struct class_attribute {
- struct attribute attr;
-diff --git a/include/linux/efi-bgrt.h b/include/linux/efi-bgrt.h
-index 051b21f..165426b 100644
---- a/include/linux/efi-bgrt.h
-+++ b/include/linux/efi-bgrt.h
-@@ -6,6 +6,7 @@
- #include <linux/acpi.h>
-
- void efi_bgrt_init(void);
-+bool efi_bgrt_probe(void);
-
- /* The BGRT data itself; only valid if bgrt_image != NULL. */
- extern void *bgrt_image;
-@@ -15,6 +16,7 @@ extern struct acpi_table_bgrt *bgrt_tab;
- #else /* !CONFIG_ACPI_BGRT */
-
- static inline void efi_bgrt_init(void) {}
-+static inline bool efi_bgrt_probe(void) { return false; }
-
- #endif /* !CONFIG_ACPI_BGRT */
-
-diff --git a/include/linux/gpio.h b/include/linux/gpio.h
-index bfe6656..cadd9d2 100644
---- a/include/linux/gpio.h
-+++ b/include/linux/gpio.h
-@@ -27,6 +27,11 @@
- #define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
- #define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
-
-+#define GPIOF_DRIVE_PULLUP (1 << 6)
-+#define GPIOF_DRIVE_PULLDOWN (1 << 7)
-+#define GPIOF_DRIVE_STRONG (1 << 8)
-+#define GPIOF_DRIVE_HIZ (1 << 9)
-+
- /**
- * struct gpio - a structure describing a GPIO with configuration
- * @gpio: the GPIO number
-@@ -156,6 +161,11 @@ static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
- return -ENOSYS;
- }
-
-+static inline int gpio_set_drive(unsigned gpio, unsigned mode)
-+{
-+ return -ENOSYS;
-+}
-+
- static inline int gpio_get_value(unsigned gpio)
- {
- /* GPIO can never have been requested or set as {in,out}put */
-diff --git a/include/linux/iio/common/st_sensors.h b/include/linux/iio/common/st_sensors.h
-new file mode 100644
-index 0000000..56d0495
---- /dev/null
-+++ b/include/linux/iio/common/st_sensors.h
-@@ -0,0 +1,289 @@
-+/*
-+ * STMicroelectronics sensors library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#ifndef ST_SENSORS_H
-+#define ST_SENSORS_H
-+
-+#include <linux/i2c.h>
-+#include <linux/spi/spi.h>
-+#include <linux/irqreturn.h>
-+#include <linux/iio/trigger.h>
-+
-+#define ST_SENSORS_TX_MAX_LENGTH 2
-+#define ST_SENSORS_RX_MAX_LENGTH 6
-+
-+#define ST_SENSORS_ODR_LIST_MAX 10
-+#define ST_SENSORS_FULLSCALE_AVL_MAX 10
-+
-+#define ST_SENSORS_NUMBER_ALL_CHANNELS 4
-+#define ST_SENSORS_NUMBER_DATA_CHANNELS 3
-+#define ST_SENSORS_ENABLE_ALL_AXIS 0x07
-+#define ST_SENSORS_BYTE_FOR_CHANNEL 2
-+#define ST_SENSORS_SCAN_X 0
-+#define ST_SENSORS_SCAN_Y 1
-+#define ST_SENSORS_SCAN_Z 2
-+#define ST_SENSORS_DEFAULT_12_REALBITS 12
-+#define ST_SENSORS_DEFAULT_16_REALBITS 16
-+#define ST_SENSORS_DEFAULT_POWER_ON_VALUE 0x01
-+#define ST_SENSORS_DEFAULT_POWER_OFF_VALUE 0x00
-+#define ST_SENSORS_DEFAULT_WAI_ADDRESS 0x0f
-+#define ST_SENSORS_DEFAULT_AXIS_ADDR 0x20
-+#define ST_SENSORS_DEFAULT_AXIS_MASK 0x07
-+#define ST_SENSORS_DEFAULT_AXIS_N_BIT 3
-+
-+#define ST_SENSORS_MAX_NAME 17
-+#define ST_SENSORS_MAX_4WAI 7
-+
-+#define ST_SENSORS_LSM_CHANNELS(device_type, index, mod, endian, bits, addr) \
-+{ \
-+ .type = device_type, \
-+ .modified = 1, \
-+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
-+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
-+ .scan_index = index, \
-+ .channel2 = mod, \
-+ .address = addr, \
-+ .scan_type = { \
-+ .sign = 's', \
-+ .realbits = bits, \
-+ .shift = 16 - bits, \
-+ .storagebits = 16, \
-+ .endianness = endian, \
-+ }, \
-+}
-+
-+#define ST_SENSOR_DEV_ATTR_SAMP_FREQ() \
-+ IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, \
-+ st_sensors_sysfs_get_sampling_frequency, \
-+ st_sensors_sysfs_set_sampling_frequency)
-+
-+#define ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL() \
-+ IIO_DEV_ATTR_SAMP_FREQ_AVAIL( \
-+ st_sensors_sysfs_sampling_frequency_avail)
-+
-+#define ST_SENSORS_DEV_ATTR_SCALE_AVAIL(name) \
-+ IIO_DEVICE_ATTR(name, S_IRUGO, \
-+ st_sensors_sysfs_scale_avail, NULL , 0);
-+
-+struct st_sensor_odr_avl {
-+ unsigned int hz;
-+ u8 value;
-+};
-+
-+struct st_sensor_odr {
-+ u8 addr;
-+ u8 mask;
-+ struct st_sensor_odr_avl odr_avl[ST_SENSORS_ODR_LIST_MAX];
-+};
-+
-+struct st_sensor_power {
-+ u8 addr;
-+ u8 mask;
-+ u8 value_off;
-+ u8 value_on;
-+};
-+
-+struct st_sensor_axis {
-+ u8 addr;
-+ u8 mask;
-+};
-+
-+struct st_sensor_fullscale_avl {
-+ unsigned int num;
-+ u8 value;
-+ unsigned int gain;
-+ unsigned int gain2;
-+};
-+
-+struct st_sensor_fullscale {
-+ u8 addr;
-+ u8 mask;
-+ struct st_sensor_fullscale_avl fs_avl[ST_SENSORS_FULLSCALE_AVL_MAX];
-+};
-+
-+/**
-+ * struct st_sensor_bdu - ST sensor device block data update
-+ * @addr: address of the register.
-+ * @mask: mask to write the block data update flag.
-+ */
-+struct st_sensor_bdu {
-+ u8 addr;
-+ u8 mask;
-+};
-+
-+/**
-+ * struct st_sensor_data_ready_irq - ST sensor device data-ready interrupt
-+ * @addr: address of the register.
-+ * @mask: mask to write the on/off value.
-+ * struct ig1 - represents the Interrupt Generator 1 of sensors.
-+ * @en_addr: address of the enable ig1 register.
-+ * @en_mask: mask to write the on/off value for enable.
-+ */
-+struct st_sensor_data_ready_irq {
-+ u8 addr;
-+ u8 mask;
-+ struct {
-+ u8 en_addr;
-+ u8 en_mask;
-+ } ig1;
-+};
-+
-+/**
-+ * struct st_sensor_transfer_buffer - ST sensor device I/O buffer
-+ * @buf_lock: Mutex to protect rx and tx buffers.
-+ * @tx_buf: Buffer used by SPI transfer function to send data to the sensors.
-+ * This buffer is used to avoid DMA not-aligned issue.
-+ * @rx_buf: Buffer used by SPI transfer to receive data from sensors.
-+ * This buffer is used to avoid DMA not-aligned issue.
-+ */
-+struct st_sensor_transfer_buffer {
-+ struct mutex buf_lock;
-+ u8 rx_buf[ST_SENSORS_RX_MAX_LENGTH];
-+ u8 tx_buf[ST_SENSORS_TX_MAX_LENGTH] ____cacheline_aligned;
-+};
-+
-+/**
-+ * struct st_sensor_transfer_function - ST sensor device I/O function
-+ * @read_byte: Function used to read one byte.
-+ * @write_byte: Function used to write one byte.
-+ * @read_multiple_byte: Function used to read multiple byte.
-+ */
-+struct st_sensor_transfer_function {
-+ int (*read_byte) (struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, u8 *res_byte);
-+ int (*write_byte) (struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, u8 data);
-+ int (*read_multiple_byte) (struct st_sensor_transfer_buffer *tb,
-+ struct device *dev, u8 reg_addr, int len, u8 *data,
-+ bool multiread_bit);
-+};
-+
-+/**
-+ * struct st_sensors - ST sensors list
-+ * @wai: Contents of WhoAmI register.
-+ * @sensors_supported: List of supported sensors by struct itself.
-+ * @ch: IIO channels for the sensor.
-+ * @odr: Output data rate register and ODR list available.
-+ * @pw: Power register of the sensor.
-+ * @enable_axis: Enable one or more axis of the sensor.
-+ * @fs: Full scale register and full scale list available.
-+ * @bdu: Block data update register.
-+ * @drdy_irq: Data ready register of the sensor.
-+ * @multi_read_bit: Use or not particular bit for [I2C/SPI] multi-read.
-+ * @bootime: samples to discard when sensor passing from power-down to power-up.
-+ */
-+struct st_sensors {
-+ u8 wai;
-+ char sensors_supported[ST_SENSORS_MAX_4WAI][ST_SENSORS_MAX_NAME];
-+ struct iio_chan_spec *ch;
-+ struct st_sensor_odr odr;
-+ struct st_sensor_power pw;
-+ struct st_sensor_axis enable_axis;
-+ struct st_sensor_fullscale fs;
-+ struct st_sensor_bdu bdu;
-+ struct st_sensor_data_ready_irq drdy_irq;
-+ bool multi_read_bit;
-+ unsigned int bootime;
-+};
-+
-+/**
-+ * struct st_sensor_data - ST sensor device status
-+ * @dev: Pointer to instance of struct device (I2C or SPI).
-+ * @trig: The trigger in use by the core driver.
-+ * @sensor: Pointer to the current sensor struct in use.
-+ * @current_fullscale: Maximum range of measure by the sensor.
-+ * @enabled: Status of the sensor (false->off, true->on).
-+ * @multiread_bit: Use or not particular bit for [I2C/SPI] multiread.
-+ * @buffer_data: Data used by buffer part.
-+ * @odr: Output data rate of the sensor [Hz].
-+ * @get_irq_data_ready: Function to get the IRQ used for data ready signal.
-+ * @tf: Transfer function structure used by I/O operations.
-+ * @tb: Transfer buffers and mutex used by I/O operations.
-+ */
-+struct st_sensor_data {
-+ struct device *dev;
-+ struct iio_trigger *trig;
-+ struct st_sensors *sensor;
-+ struct st_sensor_fullscale_avl *current_fullscale;
-+
-+ bool enabled;
-+ bool multiread_bit;
-+
-+ char *buffer_data;
-+
-+ unsigned int odr;
-+
-+ unsigned int (*get_irq_data_ready) (struct iio_dev *indio_dev);
-+
-+ const struct st_sensor_transfer_function *tf;
-+ struct st_sensor_transfer_buffer tb;
-+};
-+
-+#ifdef CONFIG_IIO_BUFFER
-+irqreturn_t st_sensors_trigger_handler(int irq, void *p);
-+
-+int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf);
-+#endif
-+
-+#ifdef CONFIG_IIO_TRIGGER
-+int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
-+ const struct iio_trigger_ops *trigger_ops);
-+
-+void st_sensors_deallocate_trigger(struct iio_dev *indio_dev);
-+
-+#else
-+static inline int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
-+ const struct iio_trigger_ops *trigger_ops)
-+{
-+ return 0;
-+}
-+static inline void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
-+{
-+ return;
-+}
-+#endif
-+
-+int st_sensors_init_sensor(struct iio_dev *indio_dev);
-+
-+int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
-+ u8 reg_addr, u8 mask, u8 data);
-+
-+int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable);
-+
-+int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable);
-+
-+int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr);
-+
-+int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable);
-+
-+int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale);
-+
-+int st_sensors_read_axis_data(struct iio_dev *indio_dev,
-+ u8 ch_addr, int *data);
-+
-+int st_sensors_read_info_raw(struct iio_dev *indio_dev,
-+ struct iio_chan_spec const *ch, int *val);
-+
-+int st_sensors_check_device_support(struct iio_dev *indio_dev,
-+ int num_sensors_list, const struct st_sensors *sensors);
-+
-+ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
-+ struct device_attribute *attr, char *buf);
-+
-+ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
-+ struct device_attribute *attr, const char *buf, size_t size);
-+
-+ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
-+ struct device_attribute *attr, char *buf);
-+
-+ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
-+ struct device_attribute *attr, char *buf);
-+
-+#endif /* ST_SENSORS_H */
-diff --git a/include/linux/iio/common/st_sensors_i2c.h b/include/linux/iio/common/st_sensors_i2c.h
-new file mode 100644
-index 0000000..67d8453
---- /dev/null
-+++ b/include/linux/iio/common/st_sensors_i2c.h
-@@ -0,0 +1,20 @@
-+/*
-+ * STMicroelectronics sensors i2c library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#ifndef ST_SENSORS_I2C_H
-+#define ST_SENSORS_I2C_H
-+
-+#include <linux/i2c.h>
-+#include <linux/iio/common/st_sensors.h>
-+
-+void st_sensors_i2c_configure(struct iio_dev *indio_dev,
-+ struct i2c_client *client, struct st_sensor_data *sdata);
-+
-+#endif /* ST_SENSORS_I2C_H */
-diff --git a/include/linux/iio/common/st_sensors_spi.h b/include/linux/iio/common/st_sensors_spi.h
-new file mode 100644
-index 0000000..d964a35
---- /dev/null
-+++ b/include/linux/iio/common/st_sensors_spi.h
-@@ -0,0 +1,20 @@
-+/*
-+ * STMicroelectronics sensors spi library driver
-+ *
-+ * Copyright 2012-2013 STMicroelectronics Inc.
-+ *
-+ * Denis Ciocca <denis.ciocca@st.com>
-+ *
-+ * Licensed under the GPL-2.
-+ */
-+
-+#ifndef ST_SENSORS_SPI_H
-+#define ST_SENSORS_SPI_H
-+
-+#include <linux/spi/spi.h>
-+#include <linux/iio/common/st_sensors.h>
-+
-+void st_sensors_spi_configure(struct iio_dev *indio_dev,
-+ struct spi_device *spi, struct st_sensor_data *sdata);
-+
-+#endif /* ST_SENSORS_SPI_H */
-diff --git a/include/linux/intel_cln_sb.h b/include/linux/intel_cln_sb.h
-new file mode 100644
-index 0000000..6092fc0
---- /dev/null
-+++ b/include/linux/intel_cln_sb.h
-@@ -0,0 +1,90 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton side-band driver
-+ *
-+ * Thread-safe sideband read/write routine.
-+ *
-+ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2012
-+ */
-+
-+#ifndef __INTEL_CLN_SB_H__
-+#define __INTEL_CLN_SB_H__
-+
-+#include <linux/types.h>
-+
-+typedef enum {
-+ SB_ID_HUNIT = 0x03,
-+ SB_ID_THERMAL = 0x04,
-+ SB_ID_ESRAM = 0x05,
-+ SB_ID_SOC = 0x31,
-+}cln_sb_id;
-+
-+/**
-+ * intel_cln_sb_read_reg
-+ *
-+ * @param cln_sb_id: Sideband identifier
-+ * @param command: Command to send to destination identifier
-+ * @param reg: Target register w/r to cln_sb_id
-+ * @return nothing
-+ *
-+ * Utility function to allow thread-safe read of side-band
-+ * command - can be different read op-code types - which is why we don't
-+ * hard-code this value directly into msg
-+ */
-+void intel_cln_sb_read_reg(cln_sb_id id, u8 cmd, u8 reg, u32 *data, u8 lock);
-+
-+/**
-+ * intel_cln_sb_write_reg
-+ *
-+ * @param cln_sb_id: Sideband identifier
-+ * @param command: Command to send to destination identifier
-+ * @param reg: Target register w/r to cln_sb_id
-+ * @return nothing
-+ *
-+ * Utility function to allow thread-safe write of side-band
-+ */
-+void intel_cln_sb_write_reg(cln_sb_id id, u8 cmd, u8 reg, u32 data, u8 lock);
-+
-+/**
-+ * intel_cln_sb_runfn_lock
-+ *
-+ * @param fn: Callback function - which requires side-band spinlock and !irq
-+ * @param arg: Callback argument
-+ * @return 0 on success < 0 on failure
-+ *
-+ * Runs the given function pointer inside of a call to the local spinlock using
-+ * spin_lock_irqsave/spin_unlock_irqrestore. Needed for the eSRAMv1 driver to
-+ * guarantee atomicity, but, available to any other user of sideband provided
-+ * rules are respected.
-+ * Rules:
-+ * fn may not sleep
-+ * fn may not change the state of irqs
-+ */
-+int intel_cln_sb_runfn_lock(int (*fn)( void * arg ), void * arg);
-+
-+/**
-+ * intel_cln_sb_initialized
-+ *
-+ * False if sideband running on non-Clanton system
-+ */
-+int intel_cln_sb_initialized(void);
-+
-+#endif /* __INTEL_CLN_SB_H__ */
-diff --git a/include/linux/intel_mid_dma.h b/include/linux/intel_mid_dma.h
-index 10496bd..a723856 100644
---- a/include/linux/intel_mid_dma.h
-+++ b/include/linux/intel_mid_dma.h
-@@ -26,8 +26,10 @@
- #define __INTEL_MID_DMA_H__
-
- #include <linux/dmaengine.h>
-+#include <linux/interrupt.h>
-
- #define DMA_PREP_CIRCULAR_LIST (1 << 10)
-+#define MAX_CHAN 4
-
- /*DMA mode configurations*/
- enum intel_mid_dma_mode {
-@@ -73,4 +75,188 @@ struct intel_mid_dma_slave {
- struct dma_slave_config dma_slave;
- };
-
-+/**
-+ * struct intel_mid_dma_chan - internal mid representation of a DMA channel
-+ * @chan: dma_chan strcture represetation for mid chan
-+ * @ch_regs: MMIO register space pointer to channel register
-+ * @dma_base: MMIO register space DMA engine base pointer
-+ * @ch_id: DMA channel id
-+ * @lock: channel spinlock
-+ * @active_list: current active descriptors
-+ * @queue: current queued up descriptors
-+ * @free_list: current free descriptors
-+ * @slave: dma slave struture
-+ * @descs_allocated: total number of decsiptors allocated
-+ * @dma: dma device struture pointer
-+ * @busy: bool representing if ch is busy (active txn) or not
-+ * @in_use: bool representing if ch is in use or not
-+ * @raw_tfr: raw trf interrupt received
-+ * @raw_block: raw block interrupt received
-+ */
-+struct intel_mid_dma_chan {
-+ struct dma_chan chan;
-+ void __iomem *ch_regs;
-+ void __iomem *dma_base;
-+ int ch_id;
-+ spinlock_t lock;
-+ struct list_head active_list;
-+ struct list_head queue;
-+ struct list_head free_list;
-+ unsigned int descs_allocated;
-+ struct middma_device *dma;
-+ bool busy;
-+ bool in_use;
-+ u32 raw_tfr;
-+ u32 raw_block;
-+ struct intel_mid_dma_slave *mid_slave;
-+};
-+
-+struct intel_mid_dma_desc {
-+ void __iomem *block; /*ch ptr*/
-+ struct list_head desc_node;
-+ struct dma_async_tx_descriptor txd;
-+ size_t len;
-+ dma_addr_t sar;
-+ dma_addr_t dar;
-+ u32 cfg_hi;
-+ u32 cfg_lo;
-+ u32 ctl_lo;
-+ u32 ctl_hi;
-+ struct pci_pool *lli_pool;
-+ struct intel_mid_dma_lli *lli;
-+ dma_addr_t lli_phys;
-+ unsigned int lli_length;
-+ unsigned int current_lli;
-+ dma_addr_t next;
-+ enum dma_transfer_direction dirn;
-+ enum dma_status status;
-+ enum dma_slave_buswidth width; /*width of DMA txn*/
-+ enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
-+
-+};
-+
-+
-+enum intel_mid_dma_state {
-+ RUNNING = 0,
-+ SUSPENDED,
-+};
-+/**
-+ * struct middma_device - internal representation of a DMA device
-+ * @pdev: PCI device
-+ * @dma_base: MMIO register space pointer of DMA
-+ * @dma_pool: for allocating DMA descriptors
-+ * @common: embedded struct dma_device
-+ * @tasklet: dma tasklet for processing interrupts
-+ * @ch: per channel data
-+ * @pci_id: DMA device PCI ID
-+ * @intr_mask: Interrupt mask to be used
-+ * @mask_reg: MMIO register for periphral mask
-+ * @chan_base: Base ch index (read from driver data)
-+ * @max_chan: max number of chs supported (from drv_data)
-+ * @block_size: Block size of DMA transfer supported (from drv_data)
-+ * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
-+ * @state: dma PM device state
-+ */
-+struct middma_device {
-+ struct pci_dev *pdev;
-+ void __iomem *dma_base;
-+ struct pci_pool *dma_pool;
-+ struct dma_device common;
-+ struct tasklet_struct tasklet;
-+ struct intel_mid_dma_chan ch[MAX_CHAN];
-+ unsigned int pci_id;
-+ unsigned int intr_mask;
-+ void __iomem *mask_reg;
-+ int chan_base;
-+ int max_chan;
-+ int block_size;
-+ bool ispci_fn;
-+ unsigned int pimr_mask;
-+ enum intel_mid_dma_state state;
-+};
-+
-+/**
-+ * struct intel_mid_dma_probe_info
-+ *
-+ * @max_chan: maximum channels to probe
-+ * @ch_base: offset from register base
-+ * @block_size: TBD
-+ * @pimr_mask: indicates if mask registers to be mapped
-+ */
-+struct intel_mid_dma_probe_info {
-+ u8 max_chan;
-+ u8 ch_base;
-+ u16 block_size;
-+ u32 pimr_mask;
-+};
-+
-+
-+/**
-+ * intel_mid_dma_interrupt - DMA ISR
-+ * @irq: IRQ where interrupt occurred
-+ * @data: ISR cllback data (the controller structure)
-+ *
-+ * See if this is our interrupt if so then schedule the tasklet
-+ * otherwise ignore
-+ */
-+irqreturn_t intel_mid_dma_interrupt(int irq, void *data);
-+
-+/**
-+ * mid_setup_dma - Setup DMA controller
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Called by remove
-+ * Unregister DMa controller, clear all structures and free interrupt
-+ */
-+int mid_setup_dma(struct pci_dev *pdev, struct middma_device *dma);
-+
-+/**
-+ * middma_shutdown - Shutdown the DMA controller
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Called by remove
-+ * Unregister DMa controller, clear all structures and free interrupt
-+ */
-+void middma_shutdown(struct pci_dev *pdev, struct middma_device *device);
-+
-+/**
-+ * intel_mid_dma_probe - PCI Probe
-+ * @pdev: Controller PCI device structure
-+ * @id: pci device id structure
-+ *
-+ * Initialize the PCI device, map BARs, query driver data.
-+ * Call intel_setup_dma to complete contoller and chan initilzation
-+ */
-+int intel_cln_dma_probe(struct pci_dev *pdev,
-+ struct middma_device *device);
-+/**
-+ * intel_mid_dma_remove - PCI remove
-+ * @pdev: Controller PCI device structure
-+ *
-+ * Free up all resources and data
-+ * Call shutdown_dma to complete contoller and chan cleanup
-+ */
-+void intel_cln_dma_remove(struct pci_dev *pdev, struct middma_device *device);
-+
-+/* Power Management */
-+/*
-+* dma_suspend - PCI suspend function
-+*
-+* @pci: PCI device structure
-+* @state: PM message
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+int intel_cln_dma_suspend(struct middma_device *device);
-+
-+/**
-+* intel_cln_dma_resume - PCI resume function
-+*
-+* @pci: PCI device structure
-+*
-+* This function is called by OS when a power event occurs
-+*/
-+int intel_cln_dma_resume(struct middma_device *device);
-+
-+
- #endif /*__INTEL_MID_DMA_H__*/
-diff --git a/include/linux/mfd/cy8c9540a.h b/include/linux/mfd/cy8c9540a.h
-new file mode 100644
-index 0000000..0fe1d70
---- /dev/null
-+++ b/include/linux/mfd/cy8c9540a.h
-@@ -0,0 +1,38 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+
-+#ifndef LINUX_CY8C9540A_PDATA_H
-+#define LINUX_CY8C9540A_PDATA_H
-+
-+#include <linux/types.h>
-+
-+#define CY8C9540A_POR_SETTINGS_LEN 147
-+#define CY8C9540A_NPWM 8
-+#define CY8C9540A_PWM_UNUSED -1
-+
-+struct cy8c9540a_pdata {
-+ u8 por_default[CY8C9540A_POR_SETTINGS_LEN];
-+ int pwm2gpio_mapping[CY8C9540A_NPWM];
-+ int gpio_base;
-+ int pwm_base;
-+ int irq_base;
-+};
-+
-+#endif
-diff --git a/include/linux/mfd/intel_cln_gip_pdata.h b/include/linux/mfd/intel_cln_gip_pdata.h
-new file mode 100644
-index 0000000..183f881
---- /dev/null
-+++ b/include/linux/mfd/intel_cln_gip_pdata.h
-@@ -0,0 +1,32 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+
-+#ifndef LINUX_INTEL_CLN_GIP_DATA_H
-+#define LINUX_INTEL_CLN_GIP_DATA_H
-+
-+struct pci_dev;
-+
-+struct intel_cln_gip_pdata {
-+ int i2c_std_mode;
-+};
-+
-+extern struct intel_cln_gip_pdata *(*intel_cln_gip_get_pdata)(void);
-+
-+#endif
-diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
-index 0eb6579..060fce2 100644
---- a/include/linux/pci_ids.h
-+++ b/include/linux/pci_ids.h
-@@ -2512,6 +2512,7 @@
- #define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823
- #define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824
- #define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F
-+#define PCI_DEVICE_ID_INTEL_CLANTON_ILB 0x095E
- #define PCI_DEVICE_ID_INTEL_I960 0x0960
- #define PCI_DEVICE_ID_INTEL_I960RM 0x0962
- #define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60
-@@ -2534,6 +2535,7 @@
- #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21
- #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30
- #define PCI_DEVICE_ID_INTEL_IOAT 0x1a38
-+#define PCI_DEVICE_ID_INTEL_CLN_SD 0x08A7
- #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
-diff --git a/include/linux/platform_data/ad7298.h b/include/linux/platform_data/ad7298.h
-index fbf8adf..721ed6f 100644
---- a/include/linux/platform_data/ad7298.h
-+++ b/include/linux/platform_data/ad7298.h
-@@ -9,12 +9,17 @@
- #ifndef __LINUX_PLATFORM_DATA_AD7298_H__
- #define __LINUX_PLATFORM_DATA_AD7298_H__
-
-+#define AD7298_MAX_CHAN 8
-+
- /**
- * struct ad7298_platform_data - Platform data for the ad7298 ADC driver
- * @ext_ref: Whether to use an external reference voltage.
-+ * @ext_vin_max: External input voltage range for each voltage input channel
-+ * (set to non-zero if platform uses external voltage dividers)
- **/
- struct ad7298_platform_data {
- bool ext_ref;
-+ u16 ext_vin_max[AD7298_MAX_CHAN];
- };
-
- #endif /* IIO_ADC_AD7298_H_ */
-diff --git a/include/linux/platform_data/clanton.h b/include/linux/platform_data/clanton.h
-new file mode 100644
-index 0000000..7f2622e
---- /dev/null
-+++ b/include/linux/platform_data/clanton.h
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+/*
-+ * Intel Clanton platform data definition
-+ */
-+
-+#ifndef _PDATA_CLANTON_H
-+#define _PDATA_CLANTON_H
-+
-+typedef enum {
-+ CLANTON_PLAT_UNDEFINED = 0,
-+ CLANTON_EMULATION = 1,
-+ CLANTON_PEAK = 2,
-+ KIPS_BAY = 3,
-+ CROSS_HILL = 4,
-+ CLANTON_HILL = 5,
-+ GALILEO = 6,
-+}cln_plat_id_t;
-+
-+typedef enum {
-+ PLAT_DATA_ID = 1,
-+ PLAT_DATA_SN = 2,
-+ PLAT_DATA_MAC0 = 3,
-+ PLAT_DATA_MAC1 = 4,
-+}plat_dataid_t;
-+
-+#endif /* _PDATA_CLANTON_H */
-diff --git a/include/linux/platform_data/lis331dlh_intel_cln.h b/include/linux/platform_data/lis331dlh_intel_cln.h
-new file mode 100644
-index 0000000..00e3006
---- /dev/null
-+++ b/include/linux/platform_data/lis331dlh_intel_cln.h
-@@ -0,0 +1,36 @@
-+/*
-+ * Platform data for Intel Clanton Hill platform accelerometer driver
-+ *
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ *
-+ */
-+
-+#ifndef __LINUX_PLATFORM_DATA_LIS331DLH_INTEL_CLN_H__
-+#define __LINUX_PLATFORM_DATA_LIS331DLH_INTEL_CLN_H__
-+
-+/**
-+ * struct lis331dlh_intel_cln_platform_data - Platform data for the ST Micro
-+ * accelerometer driver
-+ * @irq1_pin: GPIO pin number for the threshold interrupt(INT1).
-+ **/
-+struct lis331dlh_intel_cln_platform_data {
-+ int irq1_pin;
-+};
-+
-+#endif /* LINUX_PLATFORM_DATA_LIS331DLH_INTEL_CLN_H_ */
-diff --git a/include/linux/platform_data/st_accel_i2c.h b/include/linux/platform_data/st_accel_i2c.h
-new file mode 100644
-index 0000000..1dc3d93
---- /dev/null
-+++ b/include/linux/platform_data/st_accel_i2c.h
-@@ -0,0 +1,32 @@
-+/*
-+ * Copyright(c) 2013 Intel Corporation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of version 2 of the GNU General Public License as
-+ * published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-+ *
-+ * Contact Information:
-+ * Intel Corporation
-+ */
-+
-+#ifndef __LINUX_PLATFORM_DATA_ST_ACCEL_H__
-+#define __LINUX_PLATFORM_DATA_ST_ACCEL_H__
-+
-+/**
-+ * struct st_accel_i2c_platform_data - Platform data for the ST Micro accelerometer driver
-+ * @irq2: IRQ number for the second INT pin.
-+ **/
-+struct st_accel_i2c_platform_data {
-+ int irq2;
-+};
-+
-+#endif /* LINUX_PLATFORM_DATA_ST_ACCEL_H_ */
-diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
-index 1f0ab90..86ecaa6 100644
---- a/include/linux/power_supply.h
-+++ b/include/linux/power_supply.h
-@@ -224,7 +224,7 @@ struct power_supply_info {
- int use_for_apm;
- };
-
--extern struct power_supply *power_supply_get_by_name(char *name);
-+extern struct power_supply *power_supply_get_by_name(const char *name);
- extern void power_supply_changed(struct power_supply *psy);
- extern int power_supply_am_i_supplied(struct power_supply *psy);
- extern int power_supply_set_battery_charged(struct power_supply *psy);
-diff --git a/include/linux/pwm.h b/include/linux/pwm.h
-index 6d661f3..6842d11 100644
---- a/include/linux/pwm.h
-+++ b/include/linux/pwm.h
-@@ -76,6 +76,7 @@ enum pwm_polarity {
- enum {
- PWMF_REQUESTED = 1 << 0,
- PWMF_ENABLED = 1 << 1,
-+ PWMF_EXPORTED = 1 << 2,
- };
-
- struct pwm_device {
-@@ -86,7 +87,9 @@ struct pwm_device {
- struct pwm_chip *chip;
- void *chip_data;
-
-- unsigned int period; /* in nanoseconds */
-+ unsigned int period; /* in nanoseconds */
-+ unsigned int duty_cycle; /* in nanoseconds */
-+ enum pwm_polarity polarity;
- };
-
- static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
-@@ -100,6 +103,17 @@ static inline unsigned int pwm_get_period(struct pwm_device *pwm)
- return pwm ? pwm->period : 0;
- }
-
-+static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
-+{
-+ if (pwm)
-+ pwm->duty_cycle = duty;
-+}
-+
-+static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm)
-+{
-+ return pwm ? pwm->duty_cycle : 0;
-+}
-+
- /*
- * pwm_set_polarity - configure the polarity of a PWM signal
- */
-@@ -252,4 +266,17 @@ static inline void pwm_add_table(struct pwm_lookup *table, size_t num)
- }
- #endif
-
-+#ifdef CONFIG_PWM_SYSFS
-+void pwmchip_sysfs_export(struct pwm_chip *chip);
-+void pwmchip_sysfs_unexport(struct pwm_chip *chip);
-+#else
-+static inline void pwmchip_sysfs_export(struct pwm_chip *chip)
-+{
-+}
-+
-+static inline void pwmchip_sysfs_unexport(struct pwm_chip *chip)
-+{
-+}
-+#endif /* CONFIG_PWM_SYSFS */
-+
- #endif /* __LINUX_PWM_H */
-diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h
-index f366320..9810c71 100644
---- a/include/linux/pxa2xx_ssp.h
-+++ b/include/linux/pxa2xx_ssp.h
-@@ -104,6 +104,28 @@
- #define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
- #define SSCR1_RFT (0x00000c00) /* Receive FIFO Threshold (mask) */
- #define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
-+
-+/* CE5X00 SSCR0 bit definition */
-+#define CE5X00_SSCR0_DSS ((1<<5)-1) /* Data Size Select (mask) */
-+#define CE5X00_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */
-+#define CE5X00_SSCR0_FRF (((1<<2)-1) << 5) /* FRame Format (mask) */
-+#define CE5X00_SSCR0_Motorola (0x0 << 5) /* Motorola's Serial Peripheral Interface (SPI) */
-+#define CE5X00_SSCR0_TI (0x1 << 5) /* Texas Instruments' Synchronous Serial Protocol (SSP) */
-+#define CE5X00_SSCR0_National (0x2 << 5) /* National Microwire */
-+
-+#define RX_THRESH_CE5X00_DFLT 16
-+#define TX_THRESH_CE5X00_DFLT 16
-+
-+#define CE5X00_SSSR_TFL_MASK (0x1F << 8) /* Transmit FIFO Level mask */
-+#define CE5X00_SSSR_RFL_MASK (0x1F << 13) /* Receive FIFO Level mask */
-+
-+#define CE5X00_SSCR1_TFT (((1<<5)-1) << 6) /* Transmit FIFO Threshold (mask) */
-+#define CE5X00_SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..32] */
-+#define CE5X00_SSCR1_RFT (((1<<5)-1) << 11) /* Receive FIFO Threshold (mask) */
-+#define CE5X00_SSCR1_RxTresh(x) (((x) - 1) << 11) /* level [1..32] */
-+#define CE5X00_SSCR1_STRF (1 << 17) /* Select FIFO or EFWR */
-+#define CE5X00_SSCR1_EFWR (1 << 16) /* Enable FIFO Write/Read */
-+
- #endif
-
- /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
-@@ -164,6 +186,7 @@ enum pxa_ssp_type {
- PXA168_SSP,
- PXA910_SSP,
- CE4100_SSP,
-+ CE5X00_SSP,
- };
-
- struct ssp_device {
-@@ -181,6 +204,7 @@ struct ssp_device {
- int irq;
- int drcmr_rx;
- int drcmr_tx;
-+ struct pci_dev *pcidev;
- };
-
- /**
-@@ -208,4 +232,5 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
-
- struct ssp_device *pxa_ssp_request(int port, const char *label);
- void pxa_ssp_free(struct ssp_device *);
-+int pxa_msi_enabled(void);
- #endif
-diff --git a/include/linux/rtc.h b/include/linux/rtc.h
-index 9531845..445fe6e 100644
---- a/include/linux/rtc.h
-+++ b/include/linux/rtc.h
-@@ -148,7 +148,7 @@ extern int rtc_initialize_alarm(struct rtc_device *rtc,
- extern void rtc_update_irq(struct rtc_device *rtc,
- unsigned long num, unsigned long events);
-
--extern struct rtc_device *rtc_class_open(char *name);
-+extern struct rtc_device *rtc_class_open(const char *name);
- extern void rtc_class_close(struct rtc_device *rtc);
-
- extern int rtc_irq_register(struct rtc_device *rtc,
-diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h
-index c73d144..acac9ae 100644
---- a/include/linux/spi/pxa2xx_spi.h
-+++ b/include/linux/spi/pxa2xx_spi.h
-@@ -130,23 +130,12 @@ static inline void pxa_free_dma(int dma_ch)
- {
- }
-
--/*
-- * The CE4100 does not have the clk framework implemented and SPI clock can
-- * not be switched on/off or the divider changed.
-- */
--static inline void clk_disable(struct clk *clk)
--{
--}
--
--static inline int clk_enable(struct clk *clk)
--{
-- return 0;
--}
--
-+#ifndef CONFIG_GEN3_SPI
- static inline unsigned long clk_get_rate(struct clk *clk)
- {
- return 3686400;
- }
-+#endif
-
- #endif
- #endif
-diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
-index f629189..307d218 100644
---- a/include/linux/spi/spi.h
-+++ b/include/linux/spi/spi.h
-@@ -80,6 +80,8 @@ struct spi_device {
- #define SPI_MODE_2 (SPI_CPOL|0)
- #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
- #define SPI_CS_HIGH 0x04 /* chipselect active high? */
-+#define SPI_MODE_QUAD_IO 0x05 /* Quad IO mode using 4 wire */
-+#define SPI_MODE_DUAL_IO 0x06 /* Dual IO mode using 2 wire */
- #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
- #define SPI_3WIRE 0x10 /* SI/SO signals shared */
- #define SPI_LOOP 0x20 /* loopback mode */
-diff --git a/init/do_mounts.c b/init/do_mounts.c
-index 1d1b634..a2b49f2 100644
---- a/init/do_mounts.c
-+++ b/init/do_mounts.c
-@@ -81,9 +81,9 @@ struct uuidcmp {
- *
- * Returns 1 if the device matches, and 0 otherwise.
- */
--static int match_dev_by_uuid(struct device *dev, void *data)
-+static int match_dev_by_uuid(struct device *dev, const void *data)
- {
-- struct uuidcmp *cmp = data;
-+ const struct uuidcmp *cmp = data;
- struct hd_struct *part = dev_to_part(dev);
-
- if (!part->info)
-diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c
-index 25596e4..9b2a1d5 100644
---- a/kernel/power/suspend_test.c
-+++ b/kernel/power/suspend_test.c
-@@ -112,7 +112,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
- rtc_set_alarm(rtc, &alm);
- }
-
--static int __init has_wakealarm(struct device *dev, void *name_ptr)
-+static int __init has_wakealarm(struct device *dev, const void *data)
- {
- struct rtc_device *candidate = to_rtc_device(dev);
-
-@@ -121,7 +121,6 @@ static int __init has_wakealarm(struct device *dev, void *name_ptr)
- if (!device_may_wakeup(candidate->dev.parent))
- return 0;
-
-- *(const char **)name_ptr = dev_name(dev);
- return 1;
- }
-
-@@ -159,8 +158,8 @@ static int __init test_suspend(void)
- static char warn_no_rtc[] __initdata =
- KERN_WARNING "PM: no wakealarm-capable RTC driver is ready\n";
-
-- char *pony = NULL;
- struct rtc_device *rtc = NULL;
-+ struct device *dev;
-
- /* PM is initialized by now; is that state testable? */
- if (test_state == PM_SUSPEND_ON)
-@@ -171,9 +170,9 @@ static int __init test_suspend(void)
- }
-
- /* RTCs have initialized by now too ... can we use one? */
-- class_find_device(rtc_class, NULL, &pony, has_wakealarm);
-- if (pony)
-- rtc = rtc_class_open(pony);
-+ dev = class_find_device(rtc_class, NULL, NULL, has_wakealarm);
-+ if (dev)
-+ rtc = rtc_class_open(dev_name(dev));
- if (!rtc) {
- printk(warn_no_rtc);
- goto done;
-diff --git a/meta/cfg/kernel-cache/bsp/clanton/clanton.cfg b/meta/cfg/kernel-cache/bsp/clanton/clanton.cfg
-new file mode 100644
-index 0000000..3ba0d41
---- /dev/null
-+++ b/meta/cfg/kernel-cache/bsp/clanton/clanton.cfg
-@@ -0,0 +1,3044 @@
-+#
-+# Automatically generated file; DO NOT EDIT.
-+# Linux/i386 3.8.7 Kernel Configuration
-+#
-+# CONFIG_64BIT is not set
-+CONFIG_X86_32=y
-+CONFIG_X86=y
-+CONFIG_INSTRUCTION_DECODER=y
-+CONFIG_OUTPUT_FORMAT="elf32-i386"
-+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
-+CONFIG_MMU=y
-+CONFIG_NEED_SG_DMA_LENGTH=y
-+CONFIG_GENERIC_ISA_DMA=y
-+CONFIG_GENERIC_BUG=y
-+CONFIG_GENERIC_HWEIGHT=y
-+CONFIG_GENERIC_GPIO=y
-+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-+CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_ARCH_HAS_CPU_RELAX=y
-+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
-+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
-+CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
-+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
-+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-+CONFIG_ARCH_SUSPEND_POSSIBLE=y
-+# CONFIG_ZONE_DMA32 is not set
-+# CONFIG_AUDIT_ARCH is not set
-+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
-+CONFIG_X86_32_LAZY_GS=y
-+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
-+CONFIG_ARCH_SUPPORTS_UPROBES=y
-+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-+CONFIG_HAVE_IRQ_WORK=y
-+CONFIG_IRQ_WORK=y
-+CONFIG_BUILDTIME_EXTABLE_SORT=y
-+
-+#
-+# General setup
-+#
-+CONFIG_EXPERIMENTAL=y
-+CONFIG_BROKEN_ON_SMP=y
-+CONFIG_INIT_ENV_ARG_LIMIT=32
-+CONFIG_CROSS_COMPILE=""
-+CONFIG_LOCALVERSION=""
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_HAVE_KERNEL_GZIP=y
-+CONFIG_HAVE_KERNEL_BZIP2=y
-+CONFIG_HAVE_KERNEL_LZMA=y
-+CONFIG_HAVE_KERNEL_XZ=y
-+CONFIG_HAVE_KERNEL_LZO=y
-+# CONFIG_KERNEL_GZIP is not set
-+# CONFIG_KERNEL_BZIP2 is not set
-+CONFIG_KERNEL_LZMA=y
-+# CONFIG_KERNEL_XZ is not set
-+# CONFIG_KERNEL_LZO is not set
-+CONFIG_DEFAULT_HOSTNAME="(none)"
-+# CONFIG_SWAP is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_SYSVIPC_SYSCTL=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_POSIX_MQUEUE_SYSCTL=y
-+# CONFIG_FHANDLE is not set
-+# CONFIG_AUDIT is not set
-+CONFIG_HAVE_GENERIC_HARDIRQS=y
-+
-+#
-+# IRQ subsystem
-+#
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_GENERIC_IRQ_SHOW=y
-+CONFIG_GENERIC_IRQ_CHIP=y
-+CONFIG_IRQ_DOMAIN=y
-+# CONFIG_IRQ_DOMAIN_DEBUG is not set
-+CONFIG_IRQ_FORCED_THREADING=y
-+CONFIG_SPARSE_IRQ=y
-+CONFIG_CLOCKSOURCE_WATCHDOG=y
-+CONFIG_KTIME_SCALAR=y
-+CONFIG_GENERIC_CLOCKEVENTS=y
-+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
-+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
-+CONFIG_GENERIC_CMOS_UPDATE=y
-+
-+#
-+# Timers subsystem
-+#
-+CONFIG_TICK_ONESHOT=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+
-+#
-+# CPU/Task time and stats accounting
-+#
-+CONFIG_TICK_CPU_ACCOUNTING=y
-+# CONFIG_IRQ_TIME_ACCOUNTING is not set
-+CONFIG_BSD_PROCESS_ACCT=y
-+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-+# CONFIG_TASKSTATS is not set
-+
-+#
-+# RCU Subsystem
-+#
-+CONFIG_TINY_RCU=y
-+# CONFIG_PREEMPT_RCU is not set
-+# CONFIG_TREE_RCU_TRACE is not set
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_LOG_BUF_SHIFT=18
-+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
-+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
-+CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
-+CONFIG_CGROUPS=y
-+# CONFIG_CGROUP_DEBUG is not set
-+CONFIG_CGROUP_FREEZER=y
-+# CONFIG_CGROUP_DEVICE is not set
-+CONFIG_CPUSETS=y
-+CONFIG_PROC_PID_CPUSET=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_RESOURCE_COUNTERS=y
-+# CONFIG_MEMCG is not set
-+# CONFIG_CGROUP_HUGETLB is not set
-+# CONFIG_CGROUP_PERF is not set
-+CONFIG_CGROUP_SCHED=y
-+CONFIG_FAIR_GROUP_SCHED=y
-+# CONFIG_CFS_BANDWIDTH is not set
-+# CONFIG_RT_GROUP_SCHED is not set
-+# CONFIG_BLK_CGROUP is not set
-+# CONFIG_CHECKPOINT_RESTORE is not set
-+CONFIG_NAMESPACES=y
-+CONFIG_UTS_NS=y
-+CONFIG_IPC_NS=y
-+# CONFIG_USER_NS is not set
-+CONFIG_PID_NS=y
-+CONFIG_NET_NS=y
-+CONFIG_UIDGID_CONVERTED=y
-+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
-+# CONFIG_SCHED_AUTOGROUP is not set
-+# CONFIG_SYSFS_DEPRECATED is not set
-+CONFIG_RELAY=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_INITRAMFS_SOURCE=""
-+CONFIG_RD_GZIP=y
-+CONFIG_RD_BZIP2=y
-+CONFIG_RD_LZMA=y
-+# CONFIG_RD_XZ is not set
-+# CONFIG_RD_LZO is not set
-+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-+CONFIG_SYSCTL=y
-+CONFIG_ANON_INODES=y
-+CONFIG_EXPERT=y
-+CONFIG_HAVE_UID16=y
-+CONFIG_UID16=y
-+CONFIG_SYSCTL_SYSCALL=y
-+CONFIG_SYSCTL_EXCEPTION_TRACE=y
-+CONFIG_KALLSYMS=y
-+CONFIG_KALLSYMS_ALL=y
-+CONFIG_HOTPLUG=y
-+CONFIG_PRINTK=y
-+CONFIG_BUG=y
-+CONFIG_ELF_CORE=y
-+# CONFIG_PCSPKR_PLATFORM is not set
-+CONFIG_HAVE_PCSPKR_PLATFORM=y
-+CONFIG_BASE_FULL=y
-+CONFIG_FUTEX=y
-+CONFIG_EPOLL=y
-+CONFIG_SIGNALFD=y
-+CONFIG_TIMERFD=y
-+CONFIG_EVENTFD=y
-+CONFIG_SHMEM=y
-+CONFIG_AIO=y
-+CONFIG_EMBEDDED=y
-+CONFIG_HAVE_PERF_EVENTS=y
-+
-+#
-+# Kernel Performance Events And Counters
-+#
-+CONFIG_PERF_EVENTS=y
-+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
-+CONFIG_VM_EVENT_COUNTERS=y
-+CONFIG_PCI_QUIRKS=y
-+CONFIG_SLUB_DEBUG=y
-+# CONFIG_COMPAT_BRK is not set
-+# CONFIG_SLAB is not set
-+CONFIG_SLUB=y
-+# CONFIG_SLOB is not set
-+# CONFIG_PROFILING is not set
-+CONFIG_HAVE_OPROFILE=y
-+CONFIG_OPROFILE_NMI_TIMER=y
-+# CONFIG_KPROBES is not set
-+CONFIG_JUMP_LABEL=y
-+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
-+CONFIG_HAVE_IOREMAP_PROT=y
-+CONFIG_HAVE_KPROBES=y
-+CONFIG_HAVE_KRETPROBES=y
-+CONFIG_HAVE_OPTPROBES=y
-+CONFIG_HAVE_ARCH_TRACEHOOK=y
-+CONFIG_HAVE_DMA_ATTRS=y
-+CONFIG_HAVE_DMA_CONTIGUOUS=y
-+CONFIG_GENERIC_SMP_IDLE_THREAD=y
-+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
-+CONFIG_HAVE_DMA_API_DEBUG=y
-+CONFIG_HAVE_HW_BREAKPOINT=y
-+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
-+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
-+CONFIG_HAVE_PERF_EVENTS_NMI=y
-+CONFIG_HAVE_PERF_REGS=y
-+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
-+CONFIG_HAVE_ARCH_JUMP_LABEL=y
-+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
-+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
-+CONFIG_HAVE_CMPXCHG_LOCAL=y
-+CONFIG_HAVE_CMPXCHG_DOUBLE=y
-+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
-+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
-+CONFIG_SECCOMP_FILTER=y
-+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
-+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
-+CONFIG_MODULES_USE_ELF_REL=y
-+CONFIG_GENERIC_SIGALTSTACK=y
-+CONFIG_CLONE_BACKWARDS=y
-+
-+#
-+# GCOV-based kernel profiling
-+#
-+# CONFIG_GCOV_KERNEL is not set
-+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-+CONFIG_SLABINFO=y
-+CONFIG_RT_MUTEXES=y
-+CONFIG_BASE_SMALL=0
-+CONFIG_MODULES=y
-+# CONFIG_MODULE_FORCE_LOAD is not set
-+CONFIG_MODULE_UNLOAD=y
-+# CONFIG_MODULE_FORCE_UNLOAD is not set
-+# CONFIG_MODVERSIONS is not set
-+# CONFIG_MODULE_SRCVERSION_ALL is not set
-+# CONFIG_MODULE_SIG is not set
-+CONFIG_BLOCK=y
-+# CONFIG_LBDAF is not set
-+CONFIG_BLK_DEV_BSG=y
-+# CONFIG_BLK_DEV_BSGLIB is not set
-+# CONFIG_BLK_DEV_INTEGRITY is not set
-+
-+#
-+# Partition Types
-+#
-+CONFIG_PARTITION_ADVANCED=y
-+# CONFIG_ACORN_PARTITION is not set
-+# CONFIG_OSF_PARTITION is not set
-+# CONFIG_AMIGA_PARTITION is not set
-+# CONFIG_ATARI_PARTITION is not set
-+# CONFIG_MAC_PARTITION is not set
-+CONFIG_MSDOS_PARTITION=y
-+CONFIG_BSD_DISKLABEL=y
-+# CONFIG_MINIX_SUBPARTITION is not set
-+# CONFIG_SOLARIS_X86_PARTITION is not set
-+# CONFIG_UNIXWARE_DISKLABEL is not set
-+# CONFIG_LDM_PARTITION is not set
-+# CONFIG_SGI_PARTITION is not set
-+# CONFIG_ULTRIX_PARTITION is not set
-+# CONFIG_SUN_PARTITION is not set
-+# CONFIG_KARMA_PARTITION is not set
-+# CONFIG_EFI_PARTITION is not set
-+# CONFIG_SYSV68_PARTITION is not set
-+
-+#
-+# IO Schedulers
-+#
-+CONFIG_IOSCHED_NOOP=y
-+CONFIG_IOSCHED_DEADLINE=y
-+CONFIG_IOSCHED_CFQ=y
-+# CONFIG_DEFAULT_DEADLINE is not set
-+CONFIG_DEFAULT_CFQ=y
-+# CONFIG_DEFAULT_NOOP is not set
-+CONFIG_DEFAULT_IOSCHED="cfq"
-+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
-+CONFIG_INLINE_READ_UNLOCK=y
-+CONFIG_INLINE_READ_UNLOCK_IRQ=y
-+CONFIG_INLINE_WRITE_UNLOCK=y
-+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
-+CONFIG_FREEZER=y
-+
-+#
-+# Processor type and features
-+#
-+# CONFIG_ZONE_DMA is not set
-+# CONFIG_SMP is not set
-+CONFIG_X86_MPPARSE=y
-+CONFIG_X86_EXTENDED_PLATFORM=y
-+CONFIG_INTEL_QUARK_X1000_SOC=y
-+# CONFIG_X86_WANT_INTEL_MID is not set
-+# CONFIG_X86_RDC321X is not set
-+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
-+
-+#
-+# Intel Media SOC Gen3 support
-+#
-+CONFIG_ARCH_GEN3=y
-+# CONFIG_X86_32_IRIS is not set
-+CONFIG_SCHED_OMIT_FRAME_POINTER=y
-+# CONFIG_PARAVIRT_GUEST is not set
-+CONFIG_NO_BOOTMEM=y
-+# CONFIG_MEMTEST is not set
-+# CONFIG_M486 is not set
-+# CONFIG_M586 is not set
-+CONFIG_M586TSC=y
-+# CONFIG_M586MMX is not set
-+# CONFIG_M686 is not set
-+# CONFIG_MPENTIUMII is not set
-+# CONFIG_MPENTIUMIII is not set
-+# CONFIG_MPENTIUMM is not set
-+# CONFIG_MPENTIUM4 is not set
-+# CONFIG_MK6 is not set
-+# CONFIG_MK7 is not set
-+# CONFIG_MK8 is not set
-+# CONFIG_MCRUSOE is not set
-+# CONFIG_MEFFICEON is not set
-+# CONFIG_MWINCHIPC6 is not set
-+# CONFIG_MWINCHIP3D is not set
-+# CONFIG_MELAN is not set
-+# CONFIG_MGEODEGX1 is not set
-+# CONFIG_MGEODE_LX is not set
-+# CONFIG_MCYRIXIII is not set
-+# CONFIG_MVIAC3_2 is not set
-+# CONFIG_MVIAC7 is not set
-+# CONFIG_MCORE2 is not set
-+# CONFIG_MATOM is not set
-+CONFIG_X86_GENERIC=y
-+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
-+CONFIG_X86_L1_CACHE_SHIFT=6
-+# CONFIG_X86_PPRO_FENCE is not set
-+CONFIG_X86_F00F_BUG=y
-+CONFIG_X86_ALIGNMENT_16=y
-+CONFIG_X86_INTEL_USERCOPY=y
-+CONFIG_X86_TSC=y
-+CONFIG_X86_CMPXCHG64=y
-+CONFIG_X86_MINIMUM_CPU_FAMILY=5
-+# CONFIG_PROCESSOR_SELECT is not set
-+CONFIG_CPU_SUP_INTEL=y
-+CONFIG_CPU_SUP_CYRIX_32=y
-+CONFIG_CPU_SUP_AMD=y
-+CONFIG_CPU_SUP_CENTAUR=y
-+CONFIG_CPU_SUP_TRANSMETA_32=y
-+CONFIG_CPU_SUP_UMC_32=y
-+CONFIG_HPET_TIMER=y
-+CONFIG_HPET_EMULATE_RTC=y
-+CONFIG_DMI=y
-+CONFIG_NR_CPUS=1
-+# CONFIG_PREEMPT_NONE is not set
-+CONFIG_PREEMPT_VOLUNTARY=y
-+# CONFIG_PREEMPT is not set
-+CONFIG_X86_UP_APIC=y
-+CONFIG_X86_UP_IOAPIC=y
-+CONFIG_X86_LOCAL_APIC=y
-+CONFIG_X86_IO_APIC=y
-+# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
-+CONFIG_X86_MCE=y
-+CONFIG_X86_MCE_INTEL=y
-+# CONFIG_X86_MCE_AMD is not set
-+# CONFIG_X86_ANCIENT_MCE is not set
-+CONFIG_X86_MCE_THRESHOLD=y
-+# CONFIG_X86_MCE_INJECT is not set
-+CONFIG_X86_THERMAL_VECTOR=y
-+CONFIG_VM86=y
-+# CONFIG_TOSHIBA is not set
-+# CONFIG_I8K is not set
-+CONFIG_X86_REBOOTFIXUPS=y
-+CONFIG_MICROCODE=y
-+CONFIG_MICROCODE_INTEL=y
-+# CONFIG_MICROCODE_AMD is not set
-+CONFIG_MICROCODE_OLD_INTERFACE=y
-+CONFIG_X86_MSR=y
-+CONFIG_X86_CPUID=y
-+# CONFIG_NOHIGHMEM is not set
-+# CONFIG_HIGHMEM4G is not set
-+CONFIG_HIGHMEM64G=y
-+CONFIG_VMSPLIT_3G=y
-+# CONFIG_VMSPLIT_2G is not set
-+# CONFIG_VMSPLIT_1G is not set
-+CONFIG_PAGE_OFFSET=0xC0000000
-+CONFIG_HIGHMEM=y
-+CONFIG_X86_PAE=y
-+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-+CONFIG_ARCH_FLATMEM_ENABLE=y
-+CONFIG_ARCH_SPARSEMEM_ENABLE=y
-+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-+CONFIG_ILLEGAL_POINTER_VALUE=0
-+CONFIG_SELECT_MEMORY_MODEL=y
-+CONFIG_FLATMEM_MANUAL=y
-+# CONFIG_SPARSEMEM_MANUAL is not set
-+CONFIG_FLATMEM=y
-+CONFIG_FLAT_NODE_MEM_MAP=y
-+CONFIG_SPARSEMEM_STATIC=y
-+CONFIG_HAVE_MEMBLOCK=y
-+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
-+CONFIG_ARCH_DISCARD_MEMBLOCK=y
-+CONFIG_PAGEFLAGS_EXTENDED=y
-+CONFIG_SPLIT_PTLOCK_CPUS=4
-+# CONFIG_COMPACTION is not set
-+CONFIG_PHYS_ADDR_T_64BIT=y
-+CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_BOUNCE=y
-+CONFIG_VIRT_TO_BUS=y
-+# CONFIG_KSM is not set
-+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
-+# CONFIG_MEMORY_FAILURE is not set
-+# CONFIG_TRANSPARENT_HUGEPAGE is not set
-+CONFIG_CROSS_MEMORY_ATTACH=y
-+CONFIG_NEED_PER_CPU_KM=y
-+# CONFIG_CLEANCACHE is not set
-+# CONFIG_HIGHPTE is not set
-+# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
-+CONFIG_X86_RESERVE_LOW=64
-+# CONFIG_MATH_EMULATION is not set
-+# CONFIG_MTRR is not set
-+# CONFIG_ARCH_RANDOM is not set
-+CONFIG_X86_SMAP=y
-+CONFIG_EFI=y
-+CONFIG_EFI_STUB=y
-+CONFIG_EFI_CAPSULE=m
-+CONFIG_SECCOMP=y
-+# CONFIG_CC_STACKPROTECTOR is not set
-+CONFIG_HZ_100=y
-+# CONFIG_HZ_250 is not set
-+# CONFIG_HZ_300 is not set
-+# CONFIG_HZ_1000 is not set
-+CONFIG_HZ=100
-+CONFIG_SCHED_HRTICK=y
-+CONFIG_KEXEC=y
-+# CONFIG_CRASH_DUMP is not set
-+CONFIG_PHYSICAL_START=0x400000
-+# CONFIG_RELOCATABLE is not set
-+CONFIG_PHYSICAL_ALIGN=0x1000000
-+# CONFIG_COMPAT_VDSO is not set
-+# CONFIG_CMDLINE_BOOL is not set
-+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-+
-+#
-+# Power management and ACPI options
-+#
-+CONFIG_SUSPEND=y
-+CONFIG_SUSPEND_FREEZER=y
-+CONFIG_PM_SLEEP=y
-+# CONFIG_PM_AUTOSLEEP is not set
-+# CONFIG_PM_WAKELOCKS is not set
-+CONFIG_PM_RUNTIME=y
-+CONFIG_PM=y
-+CONFIG_PM_DEBUG=y
-+# CONFIG_PM_ADVANCED_DEBUG is not set
-+# CONFIG_PM_TEST_SUSPEND is not set
-+CONFIG_PM_SLEEP_DEBUG=y
-+CONFIG_PM_TRACE=y
-+CONFIG_PM_TRACE_RTC=y
-+CONFIG_ACPI=y
-+CONFIG_ACPI_SLEEP=y
-+CONFIG_ACPI_PROCFS=y
-+CONFIG_ACPI_PROCFS_POWER=y
-+CONFIG_ACPI_EC_DEBUGFS=y
-+# CONFIG_ACPI_PROC_EVENT is not set
-+CONFIG_ACPI_AC=y
-+# CONFIG_ACPI_BATTERY is not set
-+CONFIG_ACPI_BUTTON=y
-+# CONFIG_ACPI_FAN is not set
-+# CONFIG_ACPI_DOCK is not set
-+CONFIG_ACPI_I2C=y
-+CONFIG_ACPI_PROCESSOR=y
-+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
-+CONFIG_ACPI_THERMAL=y
-+# CONFIG_ACPI_CUSTOM_DSDT is not set
-+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
-+CONFIG_ACPI_BLACKLIST_YEAR=0
-+CONFIG_ACPI_DEBUG=y
-+# CONFIG_ACPI_DEBUG_FUNC_TRACE is not set
-+CONFIG_ACPI_PCI_SLOT=y
-+CONFIG_X86_PM_TIMER=y
-+# CONFIG_ACPI_CONTAINER is not set
-+# CONFIG_ACPI_SBS is not set
-+# CONFIG_ACPI_HED is not set
-+# CONFIG_ACPI_CUSTOM_METHOD is not set
-+# CONFIG_ACPI_BGRT is not set
-+# CONFIG_ACPI_APEI is not set
-+# CONFIG_SFI is not set
-+# CONFIG_APM is not set
-+
-+#
-+# CPU Frequency scaling
-+#
-+# CONFIG_CPU_FREQ is not set
-+CONFIG_CPU_IDLE=y
-+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
-+CONFIG_CPU_IDLE_GOV_LADDER=y
-+CONFIG_CPU_IDLE_GOV_MENU=y
-+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
-+# CONFIG_INTEL_IDLE is not set
-+
-+#
-+# Bus options (PCI etc.)
-+#
-+CONFIG_PCI=y
-+# CONFIG_PCI_GOBIOS is not set
-+# CONFIG_PCI_GOMMCONFIG is not set
-+# CONFIG_PCI_GODIRECT is not set
-+CONFIG_PCI_GOANY=y
-+CONFIG_PCI_BIOS=y
-+CONFIG_PCI_DIRECT=y
-+CONFIG_PCI_MMCONFIG=y
-+CONFIG_PCI_DOMAINS=y
-+# CONFIG_PCI_CNB20LE_QUIRK is not set
-+CONFIG_PCIEPORTBUS=y
-+CONFIG_PCIEAER=y
-+# CONFIG_PCIE_ECRC is not set
-+# CONFIG_PCIEAER_INJECT is not set
-+CONFIG_PCIEASPM=y
-+# CONFIG_PCIEASPM_DEBUG is not set
-+CONFIG_PCIEASPM_DEFAULT=y
-+# CONFIG_PCIEASPM_POWERSAVE is not set
-+# CONFIG_PCIEASPM_PERFORMANCE is not set
-+CONFIG_PCIE_PME=y
-+CONFIG_ARCH_SUPPORTS_MSI=y
-+CONFIG_PCI_MSI=y
-+CONFIG_PCI_DEBUG=y
-+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
-+# CONFIG_PCI_STUB is not set
-+CONFIG_HT_IRQ=y
-+# CONFIG_PCI_IOV is not set
-+# CONFIG_PCI_PRI is not set
-+# CONFIG_PCI_PASID is not set
-+CONFIG_PCI_IOAPIC=y
-+CONFIG_PCI_LABEL=y
-+CONFIG_ISA_DMA_API=y
-+# CONFIG_ISA is not set
-+# CONFIG_SCx200 is not set
-+# CONFIG_ALIX is not set
-+# CONFIG_NET5501 is not set
-+# CONFIG_GEOS is not set
-+CONFIG_AMD_NB=y
-+# CONFIG_PCCARD is not set
-+# CONFIG_HOTPLUG_PCI is not set
-+# CONFIG_RAPIDIO is not set
-+
-+#
-+# Executable file formats / Emulations
-+#
-+CONFIG_BINFMT_ELF=y
-+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
-+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
-+CONFIG_HAVE_AOUT=y
-+# CONFIG_BINFMT_AOUT is not set
-+# CONFIG_BINFMT_MISC is not set
-+CONFIG_COREDUMP=y
-+CONFIG_HAVE_ATOMIC_IOMAP=y
-+CONFIG_HAVE_TEXT_POKE_SMP=y
-+CONFIG_NET=y
-+
-+#
-+# Networking options
-+#
-+CONFIG_PACKET=y
-+# CONFIG_PACKET_DIAG is not set
-+CONFIG_UNIX=y
-+# CONFIG_UNIX_DIAG is not set
-+CONFIG_XFRM=y
-+# CONFIG_XFRM_USER is not set
-+# CONFIG_XFRM_SUB_POLICY is not set
-+# CONFIG_XFRM_MIGRATE is not set
-+# CONFIG_XFRM_STATISTICS is not set
-+# CONFIG_NET_KEY is not set
-+CONFIG_INET=y
-+# CONFIG_IP_MULTICAST is not set
-+# CONFIG_IP_ADVANCED_ROUTER is not set
-+# CONFIG_IP_PNP is not set
-+# CONFIG_NET_IPIP is not set
-+# CONFIG_NET_IPGRE_DEMUX is not set
-+# CONFIG_ARPD is not set
-+CONFIG_SYN_COOKIES=y
-+# CONFIG_NET_IPVTI is not set
-+# CONFIG_INET_AH is not set
-+# CONFIG_INET_ESP is not set
-+# CONFIG_INET_IPCOMP is not set
-+# CONFIG_INET_XFRM_TUNNEL is not set
-+# CONFIG_INET_TUNNEL is not set
-+CONFIG_INET_XFRM_MODE_TRANSPORT=y
-+CONFIG_INET_XFRM_MODE_TUNNEL=y
-+CONFIG_INET_XFRM_MODE_BEET=y
-+CONFIG_INET_LRO=y
-+CONFIG_INET_DIAG=y
-+CONFIG_INET_TCP_DIAG=y
-+# CONFIG_INET_UDP_DIAG is not set
-+# CONFIG_TCP_CONG_ADVANCED is not set
-+CONFIG_TCP_CONG_CUBIC=y
-+CONFIG_DEFAULT_TCP_CONG="cubic"
-+# CONFIG_TCP_MD5SIG is not set
-+CONFIG_IPV6=m
-+# CONFIG_IPV6_PRIVACY is not set
-+# CONFIG_IPV6_ROUTER_PREF is not set
-+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-+# CONFIG_INET6_AH is not set
-+# CONFIG_INET6_ESP is not set
-+# CONFIG_INET6_IPCOMP is not set
-+# CONFIG_IPV6_MIP6 is not set
-+# CONFIG_INET6_XFRM_TUNNEL is not set
-+# CONFIG_INET6_TUNNEL is not set
-+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET6_XFRM_MODE_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_BEET=m
-+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-+# CONFIG_IPV6_SIT is not set
-+# CONFIG_IPV6_TUNNEL is not set
-+# CONFIG_IPV6_GRE is not set
-+# CONFIG_IPV6_MULTIPLE_TABLES is not set
-+# CONFIG_IPV6_MROUTE is not set
-+# CONFIG_NETLABEL is not set
-+# CONFIG_NETWORK_SECMARK is not set
-+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
-+# CONFIG_NETFILTER is not set
-+# CONFIG_IP_DCCP is not set
-+# CONFIG_IP_SCTP is not set
-+# CONFIG_RDS is not set
-+# CONFIG_TIPC is not set
-+# CONFIG_ATM is not set
-+# CONFIG_L2TP is not set
-+CONFIG_STP=m
-+CONFIG_GARP=m
-+# CONFIG_BRIDGE is not set
-+CONFIG_HAVE_NET_DSA=y
-+CONFIG_VLAN_8021Q=m
-+CONFIG_VLAN_8021Q_GVRP=y
-+# CONFIG_DECNET is not set
-+CONFIG_LLC=m
-+# CONFIG_LLC2 is not set
-+# CONFIG_IPX is not set
-+# CONFIG_ATALK is not set
-+# CONFIG_X25 is not set
-+# CONFIG_LAPB is not set
-+# CONFIG_WAN_ROUTER is not set
-+# CONFIG_PHONET is not set
-+# CONFIG_IEEE802154 is not set
-+# CONFIG_NET_SCHED is not set
-+# CONFIG_DCB is not set
-+# CONFIG_DNS_RESOLVER is not set
-+# CONFIG_BATMAN_ADV is not set
-+# CONFIG_OPENVSWITCH is not set
-+# CONFIG_NETPRIO_CGROUP is not set
-+CONFIG_BQL=y
-+
-+#
-+# Network testing
-+#
-+# CONFIG_NET_PKTGEN is not set
-+# CONFIG_HAMRADIO is not set
-+# CONFIG_CAN is not set
-+# CONFIG_IRDA is not set
-+CONFIG_BT=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+
-+#
-+# Bluetooth device drivers
-+#
-+CONFIG_BT_HCIBTUSB=m
-+# CONFIG_BT_HCIBTSDIO is not set
-+# CONFIG_BT_HCIUART is not set
-+# CONFIG_BT_HCIBCM203X is not set
-+# CONFIG_BT_HCIBPA10X is not set
-+# CONFIG_BT_HCIBFUSB is not set
-+CONFIG_BT_HCIVHCI=m
-+# CONFIG_BT_MRVL is not set
-+# CONFIG_BT_ATH3K is not set
-+# CONFIG_AF_RXRPC is not set
-+CONFIG_WIRELESS=y
-+CONFIG_WEXT_CORE=y
-+CONFIG_WEXT_PROC=y
-+CONFIG_CFG80211=m
-+# CONFIG_NL80211_TESTMODE is not set
-+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
-+# CONFIG_CFG80211_REG_DEBUG is not set
-+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
-+CONFIG_CFG80211_DEFAULT_PS=y
-+# CONFIG_CFG80211_DEBUGFS is not set
-+# CONFIG_CFG80211_INTERNAL_REGDB is not set
-+CONFIG_CFG80211_WEXT=y
-+# CONFIG_LIB80211 is not set
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_HAS_RC=y
-+# CONFIG_MAC80211_RC_PID is not set
-+CONFIG_MAC80211_RC_MINSTREL=y
-+CONFIG_MAC80211_RC_MINSTREL_HT=y
-+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
-+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
-+# CONFIG_MAC80211_MESH is not set
-+CONFIG_MAC80211_LEDS=y
-+# CONFIG_MAC80211_DEBUGFS is not set
-+# CONFIG_MAC80211_MESSAGE_TRACING is not set
-+# CONFIG_MAC80211_DEBUG_MENU is not set
-+# CONFIG_WIMAX is not set
-+CONFIG_RFKILL=m
-+CONFIG_RFKILL_LEDS=y
-+CONFIG_RFKILL_INPUT=y
-+# CONFIG_NET_9P is not set
-+# CONFIG_CAIF is not set
-+# CONFIG_CEPH_LIB is not set
-+# CONFIG_NFC is not set
-+
-+#
-+# Device Drivers
-+#
-+
-+#
-+# Generic Driver Options
-+#
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_STANDALONE=y
-+CONFIG_PREVENT_FIRMWARE_BUILD=y
-+CONFIG_FW_LOADER=y
-+CONFIG_FIRMWARE_IN_KERNEL=y
-+CONFIG_EXTRA_FIRMWARE=""
-+# CONFIG_DEBUG_DRIVER is not set
-+CONFIG_DEBUG_DEVRES=y
-+# CONFIG_SYS_HYPERVISOR is not set
-+# CONFIG_GENERIC_CPU_DEVICES is not set
-+CONFIG_DMA_SHARED_BUFFER=y
-+# CONFIG_CMA is not set
-+
-+#
-+# Bus devices
-+#
-+# CONFIG_CONNECTOR is not set
-+CONFIG_MTD=y
-+# CONFIG_MTD_TESTS is not set
-+# CONFIG_MTD_REDBOOT_PARTS is not set
-+# CONFIG_MTD_CMDLINE_PARTS is not set
-+# CONFIG_MTD_AR7_PARTS is not set
-+
-+#
-+# User Modules And Translation Layers
-+#
-+CONFIG_MTD_CHAR=m
-+CONFIG_MTD_BLKDEVS=m
-+CONFIG_MTD_BLOCK=m
-+# CONFIG_MTD_BLOCK_RO is not set
-+# CONFIG_FTL is not set
-+# CONFIG_NFTL is not set
-+# CONFIG_INFTL is not set
-+# CONFIG_RFD_FTL is not set
-+# CONFIG_SSFDC is not set
-+# CONFIG_SM_FTL is not set
-+# CONFIG_MTD_OOPS is not set
-+
-+#
-+# RAM/ROM/Flash chip drivers
-+#
-+# CONFIG_MTD_CFI is not set
-+# CONFIG_MTD_JEDECPROBE is not set
-+CONFIG_MTD_MAP_BANK_WIDTH_1=y
-+CONFIG_MTD_MAP_BANK_WIDTH_2=y
-+CONFIG_MTD_MAP_BANK_WIDTH_4=y
-+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-+CONFIG_MTD_CFI_I1=y
-+CONFIG_MTD_CFI_I2=y
-+# CONFIG_MTD_CFI_I4 is not set
-+# CONFIG_MTD_CFI_I8 is not set
-+# CONFIG_MTD_RAM is not set
-+# CONFIG_MTD_ROM is not set
-+# CONFIG_MTD_ABSENT is not set
-+
-+#
-+# Mapping drivers for chip access
-+#
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+# CONFIG_MTD_TS5500 is not set
-+# CONFIG_MTD_INTEL_VR_NOR is not set
-+# CONFIG_MTD_PLATRAM is not set
-+
-+#
-+# Self-contained MTD device drivers
-+#
-+# CONFIG_MTD_PMC551 is not set
-+# CONFIG_MTD_DATAFLASH is not set
-+CONFIG_MTD_M25P80=m
-+CONFIG_M25PXX_USE_FAST_READ=y
-+# CONFIG_MTD_SST25L is not set
-+# CONFIG_MTD_SLRAM is not set
-+# CONFIG_MTD_PHRAM is not set
-+# CONFIG_MTD_MTDRAM is not set
-+# CONFIG_MTD_MTD_CLN_ROM is not set
-+# CONFIG_MTD_BLOCK2MTD is not set
-+
-+#
-+# Disk-On-Chip Device Drivers
-+#
-+# CONFIG_MTD_DOCG3 is not set
-+# CONFIG_MTD_NAND is not set
-+# CONFIG_MTD_ONENAND is not set
-+
-+#
-+# LPDDR flash memory drivers
-+#
-+# CONFIG_MTD_LPDDR is not set
-+# CONFIG_MTD_UBI is not set
-+# CONFIG_PARPORT is not set
-+CONFIG_PNP=y
-+# CONFIG_PNP_DEBUG_MESSAGES is not set
-+
-+#
-+# Protocols
-+#
-+CONFIG_PNPACPI=y
-+CONFIG_BLK_DEV=y
-+# CONFIG_BLK_DEV_FD is not set
-+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
-+# CONFIG_BLK_CPQ_DA is not set
-+# CONFIG_BLK_CPQ_CISS_DA is not set
-+# CONFIG_BLK_DEV_DAC960 is not set
-+# CONFIG_BLK_DEV_UMEM is not set
-+# CONFIG_BLK_DEV_COW_COMMON is not set
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
-+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-+# CONFIG_BLK_DEV_DRBD is not set
-+# CONFIG_BLK_DEV_NBD is not set
-+# CONFIG_BLK_DEV_NVME is not set
-+# CONFIG_BLK_DEV_SX8 is not set
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_BLK_DEV_RAM_COUNT=1
-+CONFIG_BLK_DEV_RAM_SIZE=81920
-+# CONFIG_BLK_DEV_XIP is not set
-+# CONFIG_CDROM_PKTCDVD is not set
-+# CONFIG_ATA_OVER_ETH is not set
-+# CONFIG_BLK_DEV_HD is not set
-+# CONFIG_BLK_DEV_RBD is not set
-+
-+#
-+# Misc devices
-+#
-+# CONFIG_SENSORS_LIS3LV02D is not set
-+# CONFIG_AD525X_DPOT is not set
-+# CONFIG_IBM_ASM is not set
-+# CONFIG_PHANTOM is not set
-+# CONFIG_INTEL_MID_PTI is not set
-+# CONFIG_SGI_IOC4 is not set
-+# CONFIG_TIFM_CORE is not set
-+# CONFIG_ICS932S401 is not set
-+# CONFIG_ENCLOSURE_SERVICES is not set
-+# CONFIG_HP_ILO is not set
-+# CONFIG_APDS9802ALS is not set
-+# CONFIG_ISL29003 is not set
-+# CONFIG_ISL29020 is not set
-+# CONFIG_SENSORS_TSL2550 is not set
-+# CONFIG_SENSORS_BH1780 is not set
-+# CONFIG_SENSORS_BH1770 is not set
-+# CONFIG_SENSORS_APDS990X is not set
-+# CONFIG_HMC6352 is not set
-+# CONFIG_DS1682 is not set
-+# CONFIG_TI_DAC7512 is not set
-+# CONFIG_VMWARE_BALLOON is not set
-+# CONFIG_BMP085_I2C is not set
-+# CONFIG_BMP085_SPI is not set
-+# CONFIG_PCH_PHUB is not set
-+# CONFIG_USB_SWITCH_FSA9480 is not set
-+# CONFIG_C2PORT is not set
-+
-+#
-+# EEPROM support
-+#
-+CONFIG_EEPROM_AT24=m
-+# CONFIG_EEPROM_AT25 is not set
-+# CONFIG_EEPROM_LEGACY is not set
-+# CONFIG_EEPROM_MAX6875 is not set
-+# CONFIG_EEPROM_93CX6 is not set
-+# CONFIG_EEPROM_93XX46 is not set
-+# CONFIG_CB710_CORE is not set
-+
-+#
-+# Texas Instruments shared transport line discipline
-+#
-+# CONFIG_TI_ST is not set
-+# CONFIG_SENSORS_LIS3_I2C is not set
-+
-+#
-+# Altera FPGA firmware download module
-+#
-+# CONFIG_ALTERA_STAPL is not set
-+CONFIG_HAVE_IDE=y
-+# CONFIG_IDE is not set
-+
-+#
-+# SCSI device support
-+#
-+CONFIG_SCSI_MOD=y
-+# CONFIG_RAID_ATTRS is not set
-+CONFIG_SCSI=y
-+CONFIG_SCSI_DMA=y
-+# CONFIG_SCSI_TGT is not set
-+# CONFIG_SCSI_NETLINK is not set
-+CONFIG_SCSI_PROC_FS=y
-+
-+#
-+# SCSI support type (disk, tape, CD-ROM)
-+#
-+CONFIG_BLK_DEV_SD=y
-+# CONFIG_CHR_DEV_ST is not set
-+# CONFIG_CHR_DEV_OSST is not set
-+# CONFIG_BLK_DEV_SR is not set
-+CONFIG_CHR_DEV_SG=y
-+# CONFIG_CHR_DEV_SCH is not set
-+# CONFIG_SCSI_MULTI_LUN is not set
-+CONFIG_SCSI_CONSTANTS=y
-+# CONFIG_SCSI_LOGGING is not set
-+# CONFIG_SCSI_SCAN_ASYNC is not set
-+
-+#
-+# SCSI Transports
-+#
-+CONFIG_SCSI_SPI_ATTRS=y
-+# CONFIG_SCSI_FC_ATTRS is not set
-+# CONFIG_SCSI_ISCSI_ATTRS is not set
-+# CONFIG_SCSI_SAS_ATTRS is not set
-+# CONFIG_SCSI_SAS_LIBSAS is not set
-+# CONFIG_SCSI_SRP_ATTRS is not set
-+# CONFIG_SCSI_LOWLEVEL is not set
-+# CONFIG_SCSI_DH is not set
-+# CONFIG_SCSI_OSD_INITIATOR is not set
-+# CONFIG_ATA is not set
-+# CONFIG_MD is not set
-+# CONFIG_TARGET_CORE is not set
-+# CONFIG_FUSION is not set
-+
-+#
-+# IEEE 1394 (FireWire) support
-+#
-+# CONFIG_FIREWIRE is not set
-+# CONFIG_FIREWIRE_NOSY is not set
-+# CONFIG_I2O is not set
-+# CONFIG_MACINTOSH_DRIVERS is not set
-+CONFIG_NETDEVICES=y
-+CONFIG_NET_CORE=y
-+# CONFIG_BONDING is not set
-+# CONFIG_DUMMY is not set
-+# CONFIG_EQUALIZER is not set
-+# CONFIG_NET_FC is not set
-+CONFIG_MII=y
-+# CONFIG_NET_TEAM is not set
-+# CONFIG_MACVLAN is not set
-+# CONFIG_VXLAN is not set
-+# CONFIG_NETCONSOLE is not set
-+# CONFIG_NETPOLL is not set
-+# CONFIG_NET_POLL_CONTROLLER is not set
-+# CONFIG_TUN is not set
-+# CONFIG_VETH is not set
-+# CONFIG_ARCNET is not set
-+
-+#
-+# CAIF transport drivers
-+#
-+
-+#
-+# Distributed Switch Architecture drivers
-+#
-+# CONFIG_NET_DSA_MV88E6XXX is not set
-+# CONFIG_NET_DSA_MV88E6060 is not set
-+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
-+# CONFIG_NET_DSA_MV88E6131 is not set
-+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
-+CONFIG_ETHERNET=y
-+# CONFIG_NET_VENDOR_3COM is not set
-+# CONFIG_NET_VENDOR_ADAPTEC is not set
-+# CONFIG_NET_VENDOR_ALTEON is not set
-+# CONFIG_NET_VENDOR_AMD is not set
-+# CONFIG_NET_VENDOR_ATHEROS is not set
-+CONFIG_NET_CADENCE=y
-+# CONFIG_ARM_AT91_ETHER is not set
-+# CONFIG_MACB is not set
-+# CONFIG_NET_VENDOR_BROADCOM is not set
-+# CONFIG_NET_VENDOR_BROCADE is not set
-+# CONFIG_NET_CALXEDA_XGMAC is not set
-+# CONFIG_NET_VENDOR_CHELSIO is not set
-+# CONFIG_NET_VENDOR_CISCO is not set
-+# CONFIG_DNET is not set
-+# CONFIG_NET_VENDOR_DEC is not set
-+# CONFIG_NET_VENDOR_DLINK is not set
-+# CONFIG_NET_VENDOR_EMULEX is not set
-+# CONFIG_NET_VENDOR_EXAR is not set
-+# CONFIG_NET_VENDOR_HP is not set
-+CONFIG_NET_VENDOR_INTEL=y
-+# CONFIG_E100 is not set
-+CONFIG_E1000=m
-+# CONFIG_E1000E is not set
-+# CONFIG_IGB is not set
-+# CONFIG_IGBVF is not set
-+# CONFIG_IXGB is not set
-+# CONFIG_IXGBE is not set
-+# CONFIG_IXGBEVF is not set
-+# CONFIG_NET_VENDOR_I825XX is not set
-+# CONFIG_IP1000 is not set
-+# CONFIG_JME is not set
-+# CONFIG_NET_VENDOR_MARVELL is not set
-+# CONFIG_NET_VENDOR_MELLANOX is not set
-+# CONFIG_NET_VENDOR_MICREL is not set
-+# CONFIG_NET_VENDOR_MICROCHIP is not set
-+# CONFIG_NET_VENDOR_MYRI is not set
-+# CONFIG_FEALNX is not set
-+# CONFIG_NET_VENDOR_NATSEMI is not set
-+# CONFIG_NET_VENDOR_NVIDIA is not set
-+# CONFIG_NET_VENDOR_OKI is not set
-+# CONFIG_ETHOC is not set
-+# CONFIG_NET_PACKET_ENGINE is not set
-+# CONFIG_NET_VENDOR_QLOGIC is not set
-+# CONFIG_NET_VENDOR_REALTEK is not set
-+# CONFIG_NET_VENDOR_RDC is not set
-+# CONFIG_NET_VENDOR_SEEQ is not set
-+# CONFIG_NET_VENDOR_SILAN is not set
-+# CONFIG_NET_VENDOR_SIS is not set
-+# CONFIG_SFC is not set
-+# CONFIG_NET_VENDOR_SMSC is not set
-+CONFIG_NET_VENDOR_STMICRO=y
-+CONFIG_STMMAC_ETH=m
-+# CONFIG_STMMAC_PLATFORM is not set
-+CONFIG_STMMAC_PCI=y
-+# CONFIG_STMMAC_DEBUG_FS is not set
-+CONFIG_STMMAC_DA=y
-+# CONFIG_STMMAC_PTP is not set
-+CONFIG_STMMAC_RING=y
-+# CONFIG_STMMAC_CHAINED is not set
-+# CONFIG_NET_VENDOR_SUN is not set
-+# CONFIG_NET_VENDOR_TEHUTI is not set
-+# CONFIG_NET_VENDOR_TI is not set
-+# CONFIG_NET_VENDOR_VIA is not set
-+# CONFIG_NET_VENDOR_WIZNET is not set
-+# CONFIG_FDDI is not set
-+# CONFIG_HIPPI is not set
-+# CONFIG_NET_SB1000 is not set
-+CONFIG_PHYLIB=y
-+
-+#
-+# MII PHY device drivers
-+#
-+# CONFIG_AT803X_PHY is not set
-+# CONFIG_AMD_PHY is not set
-+# CONFIG_MARVELL_PHY is not set
-+# CONFIG_DAVICOM_PHY is not set
-+# CONFIG_QSEMI_PHY is not set
-+# CONFIG_LXT_PHY is not set
-+# CONFIG_CICADA_PHY is not set
-+# CONFIG_VITESSE_PHY is not set
-+# CONFIG_SMSC_PHY is not set
-+# CONFIG_BROADCOM_PHY is not set
-+# CONFIG_BCM87XX_PHY is not set
-+# CONFIG_ICPLUS_PHY is not set
-+# CONFIG_REALTEK_PHY is not set
-+# CONFIG_NATIONAL_PHY is not set
-+# CONFIG_STE10XP is not set
-+# CONFIG_LSI_ET1011C_PHY is not set
-+# CONFIG_MICREL_PHY is not set
-+# CONFIG_FIXED_PHY is not set
-+# CONFIG_MDIO_BITBANG is not set
-+# CONFIG_MICREL_KS8995MA is not set
-+CONFIG_PPP=m
-+# CONFIG_PPP_BSDCOMP is not set
-+CONFIG_PPP_DEFLATE=m
-+# CONFIG_PPP_FILTER is not set
-+# CONFIG_PPP_MPPE is not set
-+# CONFIG_PPP_MULTILINK is not set
-+# CONFIG_PPPOE is not set
-+CONFIG_PPP_ASYNC=m
-+# CONFIG_PPP_SYNC_TTY is not set
-+# CONFIG_SLIP is not set
-+CONFIG_SLHC=m
-+
-+#
-+# USB Network Adapters
-+#
-+# CONFIG_USB_CATC is not set
-+# CONFIG_USB_KAWETH is not set
-+# CONFIG_USB_PEGASUS is not set
-+# CONFIG_USB_RTL8150 is not set
-+# CONFIG_USB_USBNET is not set
-+# CONFIG_USB_HSO is not set
-+# CONFIG_USB_IPHETH is not set
-+CONFIG_WLAN=y
-+# CONFIG_LIBERTAS_THINFIRM is not set
-+# CONFIG_AIRO is not set
-+# CONFIG_ATMEL is not set
-+# CONFIG_AT76C50X_USB is not set
-+# CONFIG_PRISM54 is not set
-+# CONFIG_USB_ZD1201 is not set
-+# CONFIG_USB_NET_RNDIS_WLAN is not set
-+# CONFIG_RTL8180 is not set
-+# CONFIG_RTL8187 is not set
-+# CONFIG_ADM8211 is not set
-+# CONFIG_MAC80211_HWSIM is not set
-+# CONFIG_MWL8K is not set
-+# CONFIG_ATH_CARDS is not set
-+# CONFIG_B43 is not set
-+# CONFIG_B43LEGACY is not set
-+# CONFIG_BRCMFMAC is not set
-+# CONFIG_HOSTAP is not set
-+# CONFIG_IPW2100 is not set
-+# CONFIG_IPW2200 is not set
-+CONFIG_IWLWIFI=m
-+CONFIG_IWLDVM=m
-+
-+#
-+# Debugging Options
-+#
-+# CONFIG_IWLWIFI_DEBUG is not set
-+CONFIG_IWLWIFI_P2P=y
-+# CONFIG_IWL4965 is not set
-+# CONFIG_IWL3945 is not set
-+# CONFIG_LIBERTAS is not set
-+# CONFIG_HERMES is not set
-+# CONFIG_P54_COMMON is not set
-+# CONFIG_RT2X00 is not set
-+# CONFIG_RTL8192CE is not set
-+# CONFIG_RTL8192SE is not set
-+# CONFIG_RTL8192DE is not set
-+# CONFIG_RTL8723AE is not set
-+# CONFIG_RTL8192CU is not set
-+# CONFIG_WL_TI is not set
-+# CONFIG_ZD1211RW is not set
-+# CONFIG_MWIFIEX is not set
-+
-+#
-+# Enable WiMAX (Networking options) to see the WiMAX drivers
-+#
-+# CONFIG_WAN is not set
-+# CONFIG_VMXNET3 is not set
-+# CONFIG_ISDN is not set
-+
-+#
-+# Input device support
-+#
-+CONFIG_INPUT=y
-+# CONFIG_INPUT_FF_MEMLESS is not set
-+# CONFIG_INPUT_POLLDEV is not set
-+# CONFIG_INPUT_SPARSEKMAP is not set
-+# CONFIG_INPUT_MATRIXKMAP is not set
-+
-+#
-+# Userland interfaces
-+#
-+# CONFIG_INPUT_MOUSEDEV is not set
-+# CONFIG_INPUT_JOYDEV is not set
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_INPUT_EVBUG is not set
-+
-+#
-+# Input Device Drivers
-+#
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+# CONFIG_INPUT_JOYSTICK is not set
-+# CONFIG_INPUT_TABLET is not set
-+# CONFIG_INPUT_TOUCHSCREEN is not set
-+# CONFIG_INPUT_MISC is not set
-+
-+#
-+# Hardware I/O ports
-+#
-+# CONFIG_SERIO is not set
-+# CONFIG_GAMEPORT is not set
-+
-+#
-+# Character devices
-+#
-+CONFIG_VT=y
-+CONFIG_CONSOLE_TRANSLATIONS=y
-+CONFIG_VT_CONSOLE=y
-+CONFIG_VT_CONSOLE_SLEEP=y
-+CONFIG_HW_CONSOLE=y
-+CONFIG_VT_HW_CONSOLE_BINDING=y
-+CONFIG_UNIX98_PTYS=y
-+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
-+CONFIG_LEGACY_PTYS=y
-+CONFIG_LEGACY_PTY_COUNT=32
-+CONFIG_SERIAL_NONSTANDARD=y
-+# CONFIG_ROCKETPORT is not set
-+# CONFIG_CYCLADES is not set
-+# CONFIG_MOXA_INTELLIO is not set
-+# CONFIG_MOXA_SMARTIO is not set
-+# CONFIG_SYNCLINK is not set
-+# CONFIG_SYNCLINKMP is not set
-+# CONFIG_SYNCLINK_GT is not set
-+# CONFIG_NOZOMI is not set
-+# CONFIG_ISI is not set
-+# CONFIG_N_HDLC is not set
-+# CONFIG_N_GSM is not set
-+# CONFIG_TRACE_SINK is not set
-+CONFIG_DEVKMEM=y
-+# CONFIG_STALDRV is not set
-+
-+#
-+# Serial drivers
-+#
-+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_NR_UARTS=8
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-+CONFIG_SERIAL_8250_EXTENDED=y
-+CONFIG_SERIAL_8250_MANY_PORTS=y
-+CONFIG_SERIAL_8250_SHARE_IRQ=y
-+CONFIG_SERIAL_8250_DETECT_IRQ=y
-+CONFIG_SERIAL_8250_RSA=y
-+
-+#
-+# Non-8250 serial port support
-+#
-+# CONFIG_SERIAL_MAX3100 is not set
-+# CONFIG_SERIAL_MAX310X is not set
-+# CONFIG_SERIAL_MFD_HSU is not set
-+CONFIG_SERIAL_CORE=y
-+CONFIG_SERIAL_CORE_CONSOLE=y
-+# CONFIG_SERIAL_JSM is not set
-+# CONFIG_SERIAL_SCCNXP is not set
-+# CONFIG_SERIAL_TIMBERDALE is not set
-+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-+# CONFIG_SERIAL_ALTERA_UART is not set
-+# CONFIG_SERIAL_IFX6X60 is not set
-+CONFIG_SERIAL_QUARK_UART=m
-+# CONFIG_SERIAL_PCH_UART is not set
-+# CONFIG_SERIAL_ARC is not set
-+# CONFIG_TTY_PRINTK is not set
-+# CONFIG_IPMI_HANDLER is not set
-+# CONFIG_HW_RANDOM is not set
-+# CONFIG_NVRAM is not set
-+# CONFIG_R3964 is not set
-+# CONFIG_APPLICOM is not set
-+# CONFIG_SONYPI is not set
-+# CONFIG_MWAVE is not set
-+# CONFIG_PC8736x_GPIO is not set
-+# CONFIG_NSC_GPIO is not set
-+# CONFIG_RAW_DRIVER is not set
-+CONFIG_HPET=y
-+# CONFIG_HPET_MMAP is not set
-+# CONFIG_HANGCHECK_TIMER is not set
-+# CONFIG_TCG_TPM is not set
-+# CONFIG_TELCLOCK is not set
-+CONFIG_DEVPORT=y
-+CONFIG_I2C=y
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_COMPAT=y
-+CONFIG_I2C_CHARDEV=m
-+# CONFIG_I2C_MUX is not set
-+CONFIG_I2C_HELPER_AUTO=y
-+
-+#
-+# I2C Hardware Bus support
-+#
-+
-+#
-+# PC SMBus host controller drivers
-+#
-+# CONFIG_I2C_ALI1535 is not set
-+# CONFIG_I2C_ALI1563 is not set
-+# CONFIG_I2C_ALI15X3 is not set
-+# CONFIG_I2C_AMD756 is not set
-+# CONFIG_I2C_AMD8111 is not set
-+# CONFIG_I2C_I801 is not set
-+# CONFIG_I2C_ISCH is not set
-+# CONFIG_I2C_PIIX4 is not set
-+# CONFIG_I2C_NFORCE2 is not set
-+# CONFIG_I2C_SIS5595 is not set
-+# CONFIG_I2C_SIS630 is not set
-+# CONFIG_I2C_SIS96X is not set
-+# CONFIG_I2C_VIA is not set
-+# CONFIG_I2C_VIAPRO is not set
-+
-+#
-+# ACPI drivers
-+#
-+# CONFIG_I2C_SCMI is not set
-+
-+#
-+# I2C system bus drivers (mostly embedded / system-on-chip)
-+#
-+# CONFIG_I2C_CBUS_GPIO is not set
-+# CONFIG_I2C_EG20T is not set
-+# CONFIG_I2C_GPIO is not set
-+# CONFIG_I2C_INTEL_MID is not set
-+# CONFIG_I2C_OCORES is not set
-+# CONFIG_I2C_PCA_PLATFORM is not set
-+# CONFIG_I2C_PXA_PCI is not set
-+# CONFIG_I2C_SIMTEC is not set
-+# CONFIG_I2C_XILINX is not set
-+
-+#
-+# External I2C/SMBus adapter drivers
-+#
-+# CONFIG_I2C_DIOLAN_U2C is not set
-+# CONFIG_I2C_PARPORT_LIGHT is not set
-+# CONFIG_I2C_TINY_USB is not set
-+
-+#
-+# Other I2C/SMBus bus drivers
-+#
-+# CONFIG_SCx200_ACB is not set
-+# CONFIG_I2C_STUB is not set
-+# CONFIG_I2C_DEBUG_CORE is not set
-+# CONFIG_I2C_DEBUG_ALGO is not set
-+# CONFIG_I2C_DEBUG_BUS is not set
-+CONFIG_SPI=y
-+CONFIG_SPI_DEBUG=y
-+CONFIG_GEN3_SPI=y
-+CONFIG_SPI_MASTER=y
-+
-+#
-+# SPI Master Controller Drivers
-+#
-+# CONFIG_SPI_ALTERA is not set
-+CONFIG_SPI_BITBANG=y
-+CONFIG_SPI_GPIO=y
-+# CONFIG_SPI_OC_TINY is not set
-+CONFIG_SPI_PXA2XX=m
-+CONFIG_SPI_PXA2XX_PCI=m
-+# CONFIG_SPI_CE5XX_SPI_SLAVE is not set
-+# CONFIG_SPI_SC18IS602 is not set
-+# CONFIG_SPI_TOPCLIFF_PCH is not set
-+# CONFIG_SPI_XCOMM is not set
-+# CONFIG_SPI_XILINX is not set
-+# CONFIG_SPI_DESIGNWARE is not set
-+# CONFIG_SPI_LPC_SCH is not set
-+
-+#
-+# SPI Protocol Masters
-+#
-+CONFIG_SPI_SPIDEV=m
-+# CONFIG_SPI_TLE62X0 is not set
-+# CONFIG_HSI is not set
-+
-+#
-+# PPS support
-+#
-+CONFIG_PPS=m
-+# CONFIG_PPS_DEBUG is not set
-+
-+#
-+# PPS clients support
-+#
-+# CONFIG_PPS_CLIENT_KTIMER is not set
-+# CONFIG_PPS_CLIENT_LDISC is not set
-+# CONFIG_PPS_CLIENT_GPIO is not set
-+
-+#
-+# PPS generators support
-+#
-+
-+#
-+# PTP clock support
-+#
-+CONFIG_PTP_1588_CLOCK=m
-+
-+#
-+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
-+#
-+CONFIG_PTP_1588_CLOCK_PCH=m
-+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-+CONFIG_ARCH_REQUIRE_GPIOLIB=y
-+CONFIG_GPIOLIB=y
-+CONFIG_GPIO_ACPI=y
-+# CONFIG_DEBUG_GPIO is not set
-+CONFIG_GPIO_SYSFS=y
-+
-+#
-+# Memory mapped GPIO drivers:
-+#
-+# CONFIG_GPIO_GENERIC_PLATFORM is not set
-+# CONFIG_GPIO_IT8761E is not set
-+# CONFIG_GPIO_TS5500 is not set
-+CONFIG_GPIO_SCH=m
-+# CONFIG_GPIO_ICH is not set
-+# CONFIG_GPIO_VX855 is not set
-+
-+#
-+# I2C GPIO expanders:
-+#
-+# CONFIG_GPIO_MAX7300 is not set
-+# CONFIG_GPIO_MAX732X is not set
-+# CONFIG_GPIO_PCA953X is not set
-+# CONFIG_GPIO_PCF857X is not set
-+# CONFIG_GPIO_SX150X is not set
-+# CONFIG_GPIO_ADP5588 is not set
-+
-+#
-+# PCI GPIO expanders:
-+#
-+# CONFIG_GPIO_BT8XX is not set
-+# CONFIG_GPIO_AMD8111 is not set
-+# CONFIG_GPIO_LANGWELL is not set
-+# CONFIG_GPIO_PCH is not set
-+# CONFIG_GPIO_ML_IOH is not set
-+# CONFIG_GPIO_RDC321X is not set
-+
-+#
-+# SPI GPIO expanders:
-+#
-+# CONFIG_GPIO_MAX7301 is not set
-+# CONFIG_GPIO_MCP23S08 is not set
-+# CONFIG_GPIO_MC33880 is not set
-+# CONFIG_GPIO_74X164 is not set
-+
-+#
-+# AC97 GPIO expanders:
-+#
-+
-+#
-+# MODULbus GPIO expanders:
-+#
-+
-+#
-+# USB GPIO expanders:
-+#
-+# CONFIG_W1 is not set
-+CONFIG_POWER_SUPPLY=y
-+# CONFIG_POWER_SUPPLY_DEBUG is not set
-+# CONFIG_PDA_POWER is not set
-+# CONFIG_GENERIC_ADC_BATTERY is not set
-+# CONFIG_TEST_POWER is not set
-+# CONFIG_BATTERY_DS2780 is not set
-+# CONFIG_BATTERY_DS2781 is not set
-+# CONFIG_BATTERY_DS2782 is not set
-+# CONFIG_BATTERY_SBS is not set
-+# CONFIG_BATTERY_BQ27x00 is not set
-+# CONFIG_BATTERY_MAX17040 is not set
-+# CONFIG_BATTERY_MAX17042 is not set
-+# CONFIG_CHARGER_MAX8903 is not set
-+# CONFIG_CHARGER_LP8727 is not set
-+# CONFIG_CHARGER_GPIO is not set
-+# CONFIG_CHARGER_BQ2415X is not set
-+# CONFIG_CHARGER_SMB347 is not set
-+# CONFIG_POWER_RESET is not set
-+# CONFIG_POWER_AVS is not set
-+# CONFIG_HWMON is not set
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
-+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
-+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
-+# CONFIG_FAIR_SHARE is not set
-+CONFIG_STEP_WISE=y
-+# CONFIG_USER_SPACE is not set
-+# CONFIG_WATCHDOG is not set
-+CONFIG_SSB_POSSIBLE=y
-+
-+#
-+# Sonics Silicon Backplane
-+#
-+# CONFIG_SSB is not set
-+CONFIG_BCMA_POSSIBLE=y
-+
-+#
-+# Broadcom specific AMBA
-+#
-+# CONFIG_BCMA is not set
-+
-+#
-+# Multifunction device drivers
-+#
-+CONFIG_MFD_CORE=y
-+# CONFIG_MFD_88PM860X is not set
-+# CONFIG_MFD_88PM800 is not set
-+# CONFIG_MFD_88PM805 is not set
-+# CONFIG_MFD_SM501 is not set
-+# CONFIG_MFD_RTSX_PCI is not set
-+# CONFIG_MFD_TI_AM335X_TSCADC is not set
-+# CONFIG_HTC_PASIC3 is not set
-+# CONFIG_HTC_I2CPLD is not set
-+# CONFIG_MFD_LM3533 is not set
-+# CONFIG_TPS6105X is not set
-+# CONFIG_TPS65010 is not set
-+# CONFIG_TPS6507X is not set
-+# CONFIG_MFD_TPS65217 is not set
-+# CONFIG_MFD_TPS6586X is not set
-+# CONFIG_MFD_TPS65910 is not set
-+# CONFIG_MFD_TPS65912_I2C is not set
-+# CONFIG_MFD_TPS65912_SPI is not set
-+# CONFIG_MFD_TPS80031 is not set
-+# CONFIG_TWL4030_CORE is not set
-+# CONFIG_TWL6040_CORE is not set
-+# CONFIG_MFD_STMPE is not set
-+# CONFIG_MFD_TC3589X is not set
-+# CONFIG_MFD_TMIO is not set
-+# CONFIG_MFD_SMSC is not set
-+# CONFIG_PMIC_DA903X is not set
-+# CONFIG_MFD_DA9052_SPI is not set
-+# CONFIG_MFD_DA9052_I2C is not set
-+# CONFIG_MFD_DA9055 is not set
-+# CONFIG_PMIC_ADP5520 is not set
-+# CONFIG_MFD_LP8788 is not set
-+# CONFIG_MFD_MAX77686 is not set
-+# CONFIG_MFD_MAX77693 is not set
-+# CONFIG_MFD_MAX8907 is not set
-+# CONFIG_MFD_MAX8925 is not set
-+# CONFIG_MFD_MAX8997 is not set
-+# CONFIG_MFD_MAX8998 is not set
-+# CONFIG_MFD_SEC_CORE is not set
-+# CONFIG_MFD_ARIZONA_I2C is not set
-+# CONFIG_MFD_ARIZONA_SPI is not set
-+# CONFIG_MFD_WM8400 is not set
-+# CONFIG_MFD_WM831X_I2C is not set
-+# CONFIG_MFD_WM831X_SPI is not set
-+# CONFIG_MFD_WM8350_I2C is not set
-+# CONFIG_MFD_WM8994 is not set
-+# CONFIG_MFD_PCF50633 is not set
-+# CONFIG_MFD_MC13XXX_SPI is not set
-+# CONFIG_MFD_MC13XXX_I2C is not set
-+# CONFIG_ABX500_CORE is not set
-+# CONFIG_EZX_PCAP is not set
-+# CONFIG_MFD_CS5535 is not set
-+# CONFIG_MFD_TIMBERDALE is not set
-+CONFIG_CY8C9540A=m
-+CONFIG_INTEL_CLN_GIP=m
-+CONFIG_INTEL_CLN_GIP_TEST=m
-+CONFIG_LPC_SCH=y
-+# CONFIG_LPC_ICH is not set
-+# CONFIG_MFD_RDC321X is not set
-+# CONFIG_MFD_JANZ_CMODIO is not set
-+# CONFIG_MFD_VX855 is not set
-+# CONFIG_MFD_WL1273_CORE is not set
-+# CONFIG_MFD_TPS65090 is not set
-+# CONFIG_MFD_AAT2870_CORE is not set
-+# CONFIG_MFD_RC5T583 is not set
-+# CONFIG_MFD_PALMAS is not set
-+# CONFIG_MFD_VIPERBOARD is not set
-+# CONFIG_MFD_RETU is not set
-+# CONFIG_MFD_AS3711 is not set
-+# CONFIG_REGULATOR is not set
-+CONFIG_MEDIA_SUPPORT=m
-+
-+#
-+# Multimedia core support
-+#
-+CONFIG_MEDIA_CAMERA_SUPPORT=y
-+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
-+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
-+# CONFIG_MEDIA_RADIO_SUPPORT is not set
-+# CONFIG_MEDIA_RC_SUPPORT is not set
-+# CONFIG_MEDIA_CONTROLLER is not set
-+CONFIG_VIDEO_DEV=m
-+CONFIG_VIDEO_V4L2=m
-+# CONFIG_VIDEO_ADV_DEBUG is not set
-+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
-+CONFIG_VIDEOBUF2_CORE=m
-+CONFIG_VIDEOBUF2_MEMOPS=m
-+CONFIG_VIDEOBUF2_VMALLOC=m
-+
-+#
-+# Media drivers
-+#
-+CONFIG_MEDIA_USB_SUPPORT=y
-+
-+#
-+# Webcam devices
-+#
-+CONFIG_USB_VIDEO_CLASS=m
-+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
-+# CONFIG_USB_GSPCA is not set
-+# CONFIG_USB_PWC is not set
-+# CONFIG_VIDEO_CPIA2 is not set
-+# CONFIG_USB_ZR364XX is not set
-+# CONFIG_USB_STKWEBCAM is not set
-+# CONFIG_USB_S2255 is not set
-+# CONFIG_USB_SN9C102 is not set
-+
-+#
-+# Webcam, TV (analog/digital) USB devices
-+#
-+# CONFIG_VIDEO_EM28XX is not set
-+# CONFIG_MEDIA_PCI_SUPPORT is not set
-+# CONFIG_V4L_PLATFORM_DRIVERS is not set
-+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
-+# CONFIG_V4L_TEST_DRIVERS is not set
-+
-+#
-+# Supported MMC/SDIO adapters
-+#
-+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-+
-+#
-+# Media ancillary drivers (tuners, sensors, i2c, frontends)
-+#
-+
-+#
-+# Encoders, decoders, sensors and other helper chips
-+#
-+
-+#
-+# Audio decoders, processors and mixers
-+#
-+# CONFIG_VIDEO_TVAUDIO is not set
-+# CONFIG_VIDEO_TDA7432 is not set
-+# CONFIG_VIDEO_TDA9840 is not set
-+# CONFIG_VIDEO_TEA6415C is not set
-+# CONFIG_VIDEO_TEA6420 is not set
-+# CONFIG_VIDEO_MSP3400 is not set
-+# CONFIG_VIDEO_CS5345 is not set
-+# CONFIG_VIDEO_CS53L32A is not set
-+# CONFIG_VIDEO_TLV320AIC23B is not set
-+# CONFIG_VIDEO_WM8775 is not set
-+# CONFIG_VIDEO_WM8739 is not set
-+# CONFIG_VIDEO_VP27SMPX is not set
-+
-+#
-+# RDS decoders
-+#
-+# CONFIG_VIDEO_SAA6588 is not set
-+
-+#
-+# Video decoders
-+#
-+# CONFIG_VIDEO_ADV7180 is not set
-+# CONFIG_VIDEO_ADV7183 is not set
-+# CONFIG_VIDEO_BT819 is not set
-+# CONFIG_VIDEO_BT856 is not set
-+# CONFIG_VIDEO_BT866 is not set
-+# CONFIG_VIDEO_KS0127 is not set
-+# CONFIG_VIDEO_SAA7110 is not set
-+# CONFIG_VIDEO_SAA711X is not set
-+# CONFIG_VIDEO_SAA7191 is not set
-+# CONFIG_VIDEO_TVP514X is not set
-+# CONFIG_VIDEO_TVP5150 is not set
-+# CONFIG_VIDEO_TVP7002 is not set
-+# CONFIG_VIDEO_VPX3220 is not set
-+
-+#
-+# Video and audio decoders
-+#
-+# CONFIG_VIDEO_SAA717X is not set
-+# CONFIG_VIDEO_CX25840 is not set
-+
-+#
-+# MPEG video encoders
-+#
-+# CONFIG_VIDEO_CX2341X is not set
-+
-+#
-+# Video encoders
-+#
-+# CONFIG_VIDEO_SAA7127 is not set
-+# CONFIG_VIDEO_SAA7185 is not set
-+# CONFIG_VIDEO_ADV7170 is not set
-+# CONFIG_VIDEO_ADV7175 is not set
-+# CONFIG_VIDEO_ADV7343 is not set
-+# CONFIG_VIDEO_ADV7393 is not set
-+# CONFIG_VIDEO_AK881X is not set
-+
-+#
-+# Camera sensor devices
-+#
-+# CONFIG_VIDEO_OV7670 is not set
-+# CONFIG_VIDEO_VS6624 is not set
-+# CONFIG_VIDEO_MT9V011 is not set
-+# CONFIG_VIDEO_TCM825X is not set
-+# CONFIG_VIDEO_SR030PC30 is not set
-+
-+#
-+# Flash devices
-+#
-+
-+#
-+# Video improvement chips
-+#
-+# CONFIG_VIDEO_UPD64031A is not set
-+# CONFIG_VIDEO_UPD64083 is not set
-+
-+#
-+# Miscelaneous helper chips
-+#
-+# CONFIG_VIDEO_THS7303 is not set
-+# CONFIG_VIDEO_M52790 is not set
-+
-+#
-+# Sensors used on soc_camera driver
-+#
-+
-+#
-+# Customise DVB Frontends
-+#
-+# CONFIG_DVB_AU8522_V4L is not set
-+# CONFIG_DVB_TUNER_DIB0070 is not set
-+# CONFIG_DVB_TUNER_DIB0090 is not set
-+
-+#
-+# Tools to develop new frontends
-+#
-+# CONFIG_DVB_DUMMY_FE is not set
-+
-+#
-+# Graphics support
-+#
-+# CONFIG_AGP is not set
-+# CONFIG_VGA_ARB is not set
-+# CONFIG_VGA_SWITCHEROO is not set
-+# CONFIG_DRM is not set
-+# CONFIG_STUB_POULSBO is not set
-+# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-+# CONFIG_FB is not set
-+# CONFIG_EXYNOS_VIDEO is not set
-+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-+
-+#
-+# Console display driver support
-+#
-+# CONFIG_VGA_CONSOLE is not set
-+CONFIG_DUMMY_CONSOLE=y
-+CONFIG_SOUND=m
-+# CONFIG_SOUND_OSS_CORE is not set
-+CONFIG_SND=m
-+CONFIG_SND_TIMER=m
-+CONFIG_SND_PCM=m
-+CONFIG_SND_HWDEP=m
-+CONFIG_SND_RAWMIDI=m
-+# CONFIG_SND_SEQUENCER is not set
-+# CONFIG_SND_MIXER_OSS is not set
-+# CONFIG_SND_PCM_OSS is not set
-+# CONFIG_SND_HRTIMER is not set
-+# CONFIG_SND_DYNAMIC_MINORS is not set
-+CONFIG_SND_SUPPORT_OLD_API=y
-+CONFIG_SND_VERBOSE_PROCFS=y
-+# CONFIG_SND_VERBOSE_PRINTK is not set
-+# CONFIG_SND_DEBUG is not set
-+CONFIG_SND_DMA_SGBUF=y
-+# CONFIG_SND_RAWMIDI_SEQ is not set
-+# CONFIG_SND_OPL3_LIB_SEQ is not set
-+# CONFIG_SND_OPL4_LIB_SEQ is not set
-+# CONFIG_SND_SBAWE_SEQ is not set
-+# CONFIG_SND_EMU10K1_SEQ is not set
-+CONFIG_SND_DRIVERS=y
-+# CONFIG_SND_DUMMY is not set
-+# CONFIG_SND_ALOOP is not set
-+# CONFIG_SND_MTPAV is not set
-+# CONFIG_SND_SERIAL_U16550 is not set
-+# CONFIG_SND_MPU401 is not set
-+CONFIG_SND_PCI=y
-+# CONFIG_SND_AD1889 is not set
-+# CONFIG_SND_ALS300 is not set
-+# CONFIG_SND_ALS4000 is not set
-+# CONFIG_SND_ALI5451 is not set
-+# CONFIG_SND_ASIHPI is not set
-+# CONFIG_SND_ATIIXP is not set
-+# CONFIG_SND_ATIIXP_MODEM is not set
-+# CONFIG_SND_AU8810 is not set
-+# CONFIG_SND_AU8820 is not set
-+# CONFIG_SND_AU8830 is not set
-+# CONFIG_SND_AW2 is not set
-+# CONFIG_SND_AZT3328 is not set
-+# CONFIG_SND_BT87X is not set
-+# CONFIG_SND_CA0106 is not set
-+# CONFIG_SND_CMIPCI is not set
-+# CONFIG_SND_OXYGEN is not set
-+# CONFIG_SND_CS4281 is not set
-+# CONFIG_SND_CS46XX is not set
-+# CONFIG_SND_CS5530 is not set
-+# CONFIG_SND_CS5535AUDIO is not set
-+# CONFIG_SND_CTXFI is not set
-+# CONFIG_SND_DARLA20 is not set
-+# CONFIG_SND_GINA20 is not set
-+# CONFIG_SND_LAYLA20 is not set
-+# CONFIG_SND_DARLA24 is not set
-+# CONFIG_SND_GINA24 is not set
-+# CONFIG_SND_LAYLA24 is not set
-+# CONFIG_SND_MONA is not set
-+# CONFIG_SND_MIA is not set
-+# CONFIG_SND_ECHO3G is not set
-+# CONFIG_SND_INDIGO is not set
-+# CONFIG_SND_INDIGOIO is not set
-+# CONFIG_SND_INDIGODJ is not set
-+# CONFIG_SND_INDIGOIOX is not set
-+# CONFIG_SND_INDIGODJX is not set
-+# CONFIG_SND_EMU10K1 is not set
-+# CONFIG_SND_EMU10K1X is not set
-+# CONFIG_SND_ENS1370 is not set
-+# CONFIG_SND_ENS1371 is not set
-+# CONFIG_SND_ES1938 is not set
-+# CONFIG_SND_ES1968 is not set
-+# CONFIG_SND_FM801 is not set
-+# CONFIG_SND_HDA_INTEL is not set
-+# CONFIG_SND_HDSP is not set
-+# CONFIG_SND_HDSPM is not set
-+# CONFIG_SND_ICE1712 is not set
-+# CONFIG_SND_ICE1724 is not set
-+# CONFIG_SND_INTEL8X0 is not set
-+# CONFIG_SND_INTEL8X0M is not set
-+# CONFIG_SND_KORG1212 is not set
-+# CONFIG_SND_LOLA is not set
-+# CONFIG_SND_LX6464ES is not set
-+# CONFIG_SND_MAESTRO3 is not set
-+# CONFIG_SND_MIXART is not set
-+# CONFIG_SND_NM256 is not set
-+# CONFIG_SND_PCXHR is not set
-+# CONFIG_SND_RIPTIDE is not set
-+# CONFIG_SND_RME32 is not set
-+# CONFIG_SND_RME96 is not set
-+# CONFIG_SND_RME9652 is not set
-+# CONFIG_SND_SIS7019 is not set
-+# CONFIG_SND_SONICVIBES is not set
-+# CONFIG_SND_TRIDENT is not set
-+# CONFIG_SND_VIA82XX is not set
-+# CONFIG_SND_VIA82XX_MODEM is not set
-+# CONFIG_SND_VIRTUOSO is not set
-+# CONFIG_SND_VX222 is not set
-+# CONFIG_SND_YMFPCI is not set
-+CONFIG_SND_SPI=y
-+CONFIG_SND_USB=y
-+CONFIG_SND_USB_AUDIO=m
-+# CONFIG_SND_USB_UA101 is not set
-+# CONFIG_SND_USB_USX2Y is not set
-+# CONFIG_SND_USB_CAIAQ is not set
-+# CONFIG_SND_USB_US122L is not set
-+# CONFIG_SND_USB_6FIRE is not set
-+# CONFIG_SND_SOC is not set
-+# CONFIG_SOUND_PRIME is not set
-+
-+#
-+# HID support
-+#
-+CONFIG_HID=y
-+# CONFIG_HID_BATTERY_STRENGTH is not set
-+# CONFIG_HIDRAW is not set
-+# CONFIG_UHID is not set
-+CONFIG_HID_GENERIC=y
-+
-+#
-+# Special HID drivers
-+#
-+# CONFIG_HID_A4TECH is not set
-+# CONFIG_HID_ACRUX is not set
-+# CONFIG_HID_APPLE is not set
-+# CONFIG_HID_AUREAL is not set
-+# CONFIG_HID_BELKIN is not set
-+# CONFIG_HID_CHERRY is not set
-+# CONFIG_HID_CHICONY is not set
-+# CONFIG_HID_PRODIKEYS is not set
-+# CONFIG_HID_CYPRESS is not set
-+# CONFIG_HID_DRAGONRISE is not set
-+# CONFIG_HID_EMS_FF is not set
-+# CONFIG_HID_ELECOM is not set
-+# CONFIG_HID_EZKEY is not set
-+# CONFIG_HID_HOLTEK is not set
-+# CONFIG_HID_KEYTOUCH is not set
-+# CONFIG_HID_KYE is not set
-+# CONFIG_HID_UCLOGIC is not set
-+# CONFIG_HID_WALTOP is not set
-+# CONFIG_HID_GYRATION is not set
-+# CONFIG_HID_ICADE is not set
-+# CONFIG_HID_TWINHAN is not set
-+# CONFIG_HID_KENSINGTON is not set
-+# CONFIG_HID_LCPOWER is not set
-+# CONFIG_HID_LENOVO_TPKBD is not set
-+# CONFIG_HID_LOGITECH is not set
-+# CONFIG_HID_MAGICMOUSE is not set
-+# CONFIG_HID_MICROSOFT is not set
-+# CONFIG_HID_MONTEREY is not set
-+# CONFIG_HID_MULTITOUCH is not set
-+# CONFIG_HID_NTRIG is not set
-+# CONFIG_HID_ORTEK is not set
-+# CONFIG_HID_PANTHERLORD is not set
-+# CONFIG_HID_PETALYNX is not set
-+# CONFIG_HID_PICOLCD is not set
-+# CONFIG_HID_PRIMAX is not set
-+# CONFIG_HID_PS3REMOTE is not set
-+# CONFIG_HID_ROCCAT is not set
-+# CONFIG_HID_SAITEK is not set
-+# CONFIG_HID_SAMSUNG is not set
-+# CONFIG_HID_SONY is not set
-+# CONFIG_HID_SPEEDLINK is not set
-+# CONFIG_HID_SUNPLUS is not set
-+# CONFIG_HID_GREENASIA is not set
-+# CONFIG_HID_SMARTJOYPLUS is not set
-+# CONFIG_HID_TIVO is not set
-+# CONFIG_HID_TOPSEED is not set
-+# CONFIG_HID_THRUSTMASTER is not set
-+# CONFIG_HID_WACOM is not set
-+# CONFIG_HID_WIIMOTE is not set
-+# CONFIG_HID_ZEROPLUS is not set
-+# CONFIG_HID_ZYDACRON is not set
-+# CONFIG_HID_SENSOR_HUB is not set
-+
-+#
-+# USB HID support
-+#
-+CONFIG_USB_HID=m
-+# CONFIG_HID_PID is not set
-+# CONFIG_USB_HIDDEV is not set
-+
-+#
-+# USB HID Boot Protocol drivers
-+#
-+# CONFIG_USB_KBD is not set
-+# CONFIG_USB_MOUSE is not set
-+
-+#
-+# I2C HID support
-+#
-+# CONFIG_I2C_HID is not set
-+CONFIG_USB_ARCH_HAS_OHCI=y
-+CONFIG_USB_ARCH_HAS_EHCI=y
-+CONFIG_USB_ARCH_HAS_XHCI=y
-+CONFIG_USB_SUPPORT=y
-+CONFIG_USB_COMMON=m
-+CONFIG_USB_ARCH_HAS_HCD=y
-+CONFIG_USB=m
-+# CONFIG_USB_DEBUG is not set
-+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-+
-+#
-+# Miscellaneous USB options
-+#
-+# CONFIG_USB_DYNAMIC_MINORS is not set
-+# CONFIG_USB_SUSPEND is not set
-+# CONFIG_USB_OTG_WHITELIST is not set
-+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-+# CONFIG_USB_DWC3 is not set
-+# CONFIG_USB_MON is not set
-+# CONFIG_USB_WUSB_CBAF is not set
-+
-+#
-+# USB Host Controller Drivers
-+#
-+# CONFIG_USB_C67X00_HCD is not set
-+# CONFIG_USB_XHCI_HCD is not set
-+CONFIG_USB_EHCI_HCD=m
-+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-+CONFIG_USB_EHCI_TT_NEWSCHED=y
-+CONFIG_USB_EHCI_PCI=m
-+# CONFIG_USB_OXU210HP_HCD is not set
-+# CONFIG_USB_ISP116X_HCD is not set
-+# CONFIG_USB_ISP1760_HCD is not set
-+# CONFIG_USB_ISP1362_HCD is not set
-+CONFIG_USB_OHCI_HCD=m
-+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
-+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
-+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
-+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
-+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-+CONFIG_USB_UHCI_HCD=m
-+# CONFIG_USB_SL811_HCD is not set
-+# CONFIG_USB_R8A66597_HCD is not set
-+# CONFIG_USB_MUSB_HDRC is not set
-+# CONFIG_USB_CHIPIDEA is not set
-+# CONFIG_USB_RENESAS_USBHS is not set
-+
-+#
-+# USB Device Class drivers
-+#
-+CONFIG_USB_ACM=m
-+# CONFIG_USB_PRINTER is not set
-+# CONFIG_USB_WDM is not set
-+# CONFIG_USB_TMC is not set
-+
-+#
-+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
-+#
-+
-+#
-+# also be needed; see USB_STORAGE Help for more info
-+#
-+CONFIG_USB_STORAGE=m
-+# CONFIG_USB_STORAGE_DEBUG is not set
-+# CONFIG_USB_STORAGE_REALTEK is not set
-+# CONFIG_USB_STORAGE_DATAFAB is not set
-+# CONFIG_USB_STORAGE_FREECOM is not set
-+# CONFIG_USB_STORAGE_ISD200 is not set
-+# CONFIG_USB_STORAGE_USBAT is not set
-+# CONFIG_USB_STORAGE_SDDR09 is not set
-+# CONFIG_USB_STORAGE_SDDR55 is not set
-+# CONFIG_USB_STORAGE_JUMPSHOT is not set
-+# CONFIG_USB_STORAGE_ALAUDA is not set
-+# CONFIG_USB_STORAGE_ONETOUCH is not set
-+# CONFIG_USB_STORAGE_KARMA is not set
-+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
-+
-+#
-+# USB Imaging devices
-+#
-+# CONFIG_USB_MDC800 is not set
-+# CONFIG_USB_MICROTEK is not set
-+
-+#
-+# USB port drivers
-+#
-+CONFIG_USB_SERIAL=m
-+CONFIG_USB_SERIAL_GENERIC=y
-+# CONFIG_USB_SERIAL_AIRCABLE is not set
-+# CONFIG_USB_SERIAL_ARK3116 is not set
-+# CONFIG_USB_SERIAL_BELKIN is not set
-+# CONFIG_USB_SERIAL_CH341 is not set
-+# CONFIG_USB_SERIAL_WHITEHEAT is not set
-+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-+# CONFIG_USB_SERIAL_CP210X is not set
-+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
-+# CONFIG_USB_SERIAL_EMPEG is not set
-+# CONFIG_USB_SERIAL_FTDI_SIO is not set
-+# CONFIG_USB_SERIAL_FUNSOFT is not set
-+# CONFIG_USB_SERIAL_VISOR is not set
-+# CONFIG_USB_SERIAL_IPAQ is not set
-+# CONFIG_USB_SERIAL_IR is not set
-+# CONFIG_USB_SERIAL_EDGEPORT is not set
-+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-+# CONFIG_USB_SERIAL_F81232 is not set
-+# CONFIG_USB_SERIAL_GARMIN is not set
-+# CONFIG_USB_SERIAL_IPW is not set
-+# CONFIG_USB_SERIAL_IUU is not set
-+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-+# CONFIG_USB_SERIAL_KEYSPAN is not set
-+# CONFIG_USB_SERIAL_KLSI is not set
-+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-+# CONFIG_USB_SERIAL_MCT_U232 is not set
-+# CONFIG_USB_SERIAL_METRO is not set
-+# CONFIG_USB_SERIAL_MOS7720 is not set
-+# CONFIG_USB_SERIAL_MOS7840 is not set
-+# CONFIG_USB_SERIAL_MOTOROLA is not set
-+# CONFIG_USB_SERIAL_NAVMAN is not set
-+CONFIG_USB_SERIAL_PL2303=m
-+# CONFIG_USB_SERIAL_OTI6858 is not set
-+# CONFIG_USB_SERIAL_QCAUX is not set
-+# CONFIG_USB_SERIAL_QUALCOMM is not set
-+# CONFIG_USB_SERIAL_SPCP8X5 is not set
-+# CONFIG_USB_SERIAL_HP4X is not set
-+# CONFIG_USB_SERIAL_SAFE is not set
-+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
-+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
-+# CONFIG_USB_SERIAL_SYMBOL is not set
-+# CONFIG_USB_SERIAL_TI is not set
-+# CONFIG_USB_SERIAL_CYBERJACK is not set
-+# CONFIG_USB_SERIAL_XIRCOM is not set
-+# CONFIG_USB_SERIAL_OPTION is not set
-+# CONFIG_USB_SERIAL_OMNINET is not set
-+# CONFIG_USB_SERIAL_OPTICON is not set
-+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
-+# CONFIG_USB_SERIAL_ZIO is not set
-+# CONFIG_USB_SERIAL_ZTE is not set
-+# CONFIG_USB_SERIAL_SSU100 is not set
-+# CONFIG_USB_SERIAL_QT2 is not set
-+# CONFIG_USB_SERIAL_DEBUG is not set
-+
-+#
-+# USB Miscellaneous drivers
-+#
-+# CONFIG_USB_EMI62 is not set
-+# CONFIG_USB_EMI26 is not set
-+# CONFIG_USB_ADUTUX is not set
-+# CONFIG_USB_SEVSEG is not set
-+# CONFIG_USB_RIO500 is not set
-+# CONFIG_USB_LEGOTOWER is not set
-+# CONFIG_USB_LCD is not set
-+# CONFIG_USB_LED is not set
-+# CONFIG_USB_CYPRESS_CY7C63 is not set
-+# CONFIG_USB_CYTHERM is not set
-+# CONFIG_USB_IDMOUSE is not set
-+# CONFIG_USB_FTDI_ELAN is not set
-+# CONFIG_USB_APPLEDISPLAY is not set
-+# CONFIG_USB_SISUSBVGA is not set
-+# CONFIG_USB_LD is not set
-+# CONFIG_USB_TRANCEVIBRATOR is not set
-+# CONFIG_USB_IOWARRIOR is not set
-+# CONFIG_USB_TEST is not set
-+# CONFIG_USB_ISIGHTFW is not set
-+# CONFIG_USB_YUREX is not set
-+# CONFIG_USB_EZUSB_FX2 is not set
-+
-+#
-+# USB Physical Layer drivers
-+#
-+# CONFIG_USB_ISP1301 is not set
-+# CONFIG_USB_RCAR_PHY is not set
-+CONFIG_USB_GADGET=m
-+# CONFIG_USB_GADGET_DEBUG is not set
-+# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+# CONFIG_USB_GADGET_DEBUG_FS is not set
-+CONFIG_USB_GADGET_VBUS_DRAW=2
-+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
-+
-+#
-+# USB Peripheral Controller
-+#
-+# CONFIG_USB_R8A66597 is not set
-+# CONFIG_USB_MV_UDC is not set
-+# CONFIG_USB_M66592 is not set
-+# CONFIG_USB_AMD5536UDC is not set
-+# CONFIG_USB_NET2272 is not set
-+# CONFIG_USB_NET2280 is not set
-+# CONFIG_USB_GOKU is not set
-+CONFIG_USB_EG20T=m
-+# CONFIG_USB_DUMMY_HCD is not set
-+CONFIG_USB_LIBCOMPOSITE=m
-+CONFIG_USB_ZERO=m
-+# CONFIG_USB_AUDIO is not set
-+CONFIG_USB_ETH=m
-+CONFIG_USB_ETH_RNDIS=y
-+# CONFIG_USB_ETH_EEM is not set
-+# CONFIG_USB_G_NCM is not set
-+# CONFIG_USB_GADGETFS is not set
-+# CONFIG_USB_FUNCTIONFS is not set
-+CONFIG_USB_MASS_STORAGE=m
-+CONFIG_USB_G_SERIAL=m
-+# CONFIG_USB_MIDI_GADGET is not set
-+# CONFIG_USB_G_PRINTER is not set
-+# CONFIG_USB_CDC_COMPOSITE is not set
-+# CONFIG_USB_G_ACM_MS is not set
-+# CONFIG_USB_G_MULTI is not set
-+# CONFIG_USB_G_HID is not set
-+# CONFIG_USB_G_DBGP is not set
-+# CONFIG_USB_G_WEBCAM is not set
-+
-+#
-+# OTG and related infrastructure
-+#
-+# CONFIG_USB_GPIO_VBUS is not set
-+# CONFIG_NOP_USB_XCEIV is not set
-+# CONFIG_UWB is not set
-+CONFIG_MMC=m
-+# CONFIG_MMC_DEBUG is not set
-+# CONFIG_MMC_UNSAFE_RESUME is not set
-+# CONFIG_MMC_CLKGATE is not set
-+
-+#
-+# MMC/SD/SDIO Card Drivers
-+#
-+CONFIG_MMC_BLOCK=m
-+CONFIG_MMC_BLOCK_MINORS=8
-+CONFIG_MMC_BLOCK_BOUNCE=y
-+# CONFIG_SDIO_UART is not set
-+# CONFIG_MMC_TEST is not set
-+
-+#
-+# MMC/SD/SDIO Host Controller Drivers
-+#
-+CONFIG_MMC_SDHCI=m
-+CONFIG_MMC_SDHCI_PCI=m
-+# CONFIG_MMC_RICOH_MMC is not set
-+# CONFIG_MMC_SDHCI_ACPI is not set
-+CONFIG_MMC_SDHCI_PLTFM=m
-+# CONFIG_MMC_WBSD is not set
-+# CONFIG_MMC_TIFM_SD is not set
-+# CONFIG_MMC_CB710 is not set
-+# CONFIG_MMC_VIA_SDMMC is not set
-+# CONFIG_MMC_VUB300 is not set
-+# CONFIG_MMC_USHC is not set
-+# CONFIG_MEMSTICK is not set
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=m
-+
-+#
-+# LED drivers
-+#
-+# CONFIG_LEDS_LM3530 is not set
-+# CONFIG_LEDS_LM3642 is not set
-+# CONFIG_LEDS_PCA9532 is not set
-+# CONFIG_LEDS_GPIO is not set
-+# CONFIG_LEDS_LP3944 is not set
-+# CONFIG_LEDS_LP5521 is not set
-+# CONFIG_LEDS_LP5523 is not set
-+# CONFIG_LEDS_PCA955X is not set
-+# CONFIG_LEDS_PCA9633 is not set
-+# CONFIG_LEDS_DAC124S085 is not set
-+# CONFIG_LEDS_BD2802 is not set
-+# CONFIG_LEDS_INTEL_SS4200 is not set
-+# CONFIG_LEDS_LT3593 is not set
-+# CONFIG_LEDS_TCA6507 is not set
-+# CONFIG_LEDS_LM355x is not set
-+# CONFIG_LEDS_OT200 is not set
-+# CONFIG_LEDS_BLINKM is not set
-+CONFIG_LEDS_TRIGGERS=y
-+
-+#
-+# LED Triggers
-+#
-+# CONFIG_LEDS_TRIGGER_TIMER is not set
-+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
-+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
-+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
-+# CONFIG_LEDS_TRIGGER_CPU is not set
-+# CONFIG_LEDS_TRIGGER_GPIO is not set
-+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
-+
-+#
-+# iptables trigger is under Netfilter config (LED target)
-+#
-+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
-+# CONFIG_ACCESSIBILITY is not set
-+# CONFIG_INFINIBAND is not set
-+# CONFIG_EDAC is not set
-+CONFIG_RTC_LIB=y
-+CONFIG_RTC_CLASS=y
-+CONFIG_RTC_HCTOSYS=y
-+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
-+# CONFIG_RTC_DEBUG is not set
-+
-+#
-+# RTC interfaces
-+#
-+CONFIG_RTC_INTF_SYSFS=y
-+CONFIG_RTC_INTF_PROC=y
-+CONFIG_RTC_INTF_DEV=y
-+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
-+# CONFIG_RTC_DRV_TEST is not set
-+
-+#
-+# I2C RTC drivers
-+#
-+# CONFIG_RTC_DRV_DS1307 is not set
-+# CONFIG_RTC_DRV_DS1374 is not set
-+# CONFIG_RTC_DRV_DS1672 is not set
-+# CONFIG_RTC_DRV_DS3232 is not set
-+# CONFIG_RTC_DRV_MAX6900 is not set
-+# CONFIG_RTC_DRV_RS5C372 is not set
-+# CONFIG_RTC_DRV_ISL1208 is not set
-+# CONFIG_RTC_DRV_ISL12022 is not set
-+# CONFIG_RTC_DRV_X1205 is not set
-+# CONFIG_RTC_DRV_PCF8523 is not set
-+# CONFIG_RTC_DRV_PCF8563 is not set
-+# CONFIG_RTC_DRV_PCF8583 is not set
-+# CONFIG_RTC_DRV_M41T80 is not set
-+# CONFIG_RTC_DRV_BQ32K is not set
-+# CONFIG_RTC_DRV_S35390A is not set
-+# CONFIG_RTC_DRV_FM3130 is not set
-+# CONFIG_RTC_DRV_RX8581 is not set
-+# CONFIG_RTC_DRV_RX8025 is not set
-+# CONFIG_RTC_DRV_EM3027 is not set
-+# CONFIG_RTC_DRV_RV3029C2 is not set
-+
-+#
-+# SPI RTC drivers
-+#
-+# CONFIG_RTC_DRV_M41T93 is not set
-+# CONFIG_RTC_DRV_M41T94 is not set
-+# CONFIG_RTC_DRV_DS1305 is not set
-+# CONFIG_RTC_DRV_DS1390 is not set
-+# CONFIG_RTC_DRV_MAX6902 is not set
-+# CONFIG_RTC_DRV_R9701 is not set
-+# CONFIG_RTC_DRV_RS5C348 is not set
-+# CONFIG_RTC_DRV_DS3234 is not set
-+# CONFIG_RTC_DRV_PCF2123 is not set
-+
-+#
-+# Platform RTC drivers
-+#
-+CONFIG_RTC_DRV_CMOS=y
-+# CONFIG_RTC_DRV_DS1286 is not set
-+# CONFIG_RTC_DRV_DS1511 is not set
-+# CONFIG_RTC_DRV_DS1553 is not set
-+# CONFIG_RTC_DRV_DS1742 is not set
-+# CONFIG_RTC_DRV_STK17TA8 is not set
-+# CONFIG_RTC_DRV_M48T86 is not set
-+# CONFIG_RTC_DRV_M48T35 is not set
-+# CONFIG_RTC_DRV_M48T59 is not set
-+# CONFIG_RTC_DRV_MSM6242 is not set
-+# CONFIG_RTC_DRV_BQ4802 is not set
-+# CONFIG_RTC_DRV_RP5C01 is not set
-+# CONFIG_RTC_DRV_V3020 is not set
-+# CONFIG_RTC_DRV_DS2404 is not set
-+
-+#
-+# on-CPU RTC drivers
-+#
-+CONFIG_DMADEVICES=y
-+# CONFIG_DMADEVICES_DEBUG is not set
-+
-+#
-+# DMA Devices
-+#
-+CONFIG_INTEL_MID_DMAC=m
-+# CONFIG_INTEL_IOATDMA is not set
-+# CONFIG_TIMB_DMA is not set
-+# CONFIG_PCH_DMA is not set
-+CONFIG_DMA_ENGINE=y
-+
-+#
-+# DMA Clients
-+#
-+# CONFIG_NET_DMA is not set
-+# CONFIG_ASYNC_TX_DMA is not set
-+# CONFIG_DMATEST is not set
-+# CONFIG_AUXDISPLAY is not set
-+CONFIG_UIO=m
-+# CONFIG_UIO_CIF is not set
-+# CONFIG_UIO_PDRV is not set
-+# CONFIG_UIO_PDRV_GENIRQ is not set
-+# CONFIG_UIO_DMEM_GENIRQ is not set
-+# CONFIG_UIO_AEC is not set
-+# CONFIG_UIO_SERCOS3 is not set
-+# CONFIG_UIO_PCI_GENERIC is not set
-+# CONFIG_UIO_NETX is not set
-+
-+#
-+# Virtio drivers
-+#
-+# CONFIG_VIRTIO_PCI is not set
-+# CONFIG_VIRTIO_MMIO is not set
-+
-+#
-+# Microsoft Hyper-V guest support
-+#
-+# CONFIG_HYPERV is not set
-+CONFIG_STAGING=y
-+# CONFIG_ET131X is not set
-+# CONFIG_SLICOSS is not set
-+# CONFIG_USBIP_CORE is not set
-+# CONFIG_W35UND is not set
-+# CONFIG_PRISM2_USB is not set
-+# CONFIG_ECHO is not set
-+# CONFIG_COMEDI is not set
-+# CONFIG_ASUS_OLED is not set
-+# CONFIG_R8187SE is not set
-+# CONFIG_RTL8192U is not set
-+# CONFIG_RTLLIB is not set
-+# CONFIG_R8712U is not set
-+# CONFIG_RTS5139 is not set
-+# CONFIG_TRANZPORT is not set
-+# CONFIG_LINE6_USB is not set
-+# CONFIG_USB_SERIAL_QUATECH2 is not set
-+# CONFIG_VT6655 is not set
-+# CONFIG_VT6656 is not set
-+# CONFIG_DX_SEP is not set
-+
-+#
-+# IIO staging drivers
-+#
-+# CONFIG_IIO_SW_RING is not set
-+
-+#
-+# Accelerometers
-+#
-+# CONFIG_ADIS16201 is not set
-+# CONFIG_ADIS16203 is not set
-+# CONFIG_ADIS16204 is not set
-+# CONFIG_ADIS16209 is not set
-+# CONFIG_ADIS16220 is not set
-+# CONFIG_ADIS16240 is not set
-+# CONFIG_KXSD9 is not set
-+# CONFIG_LIS3L02DQ is not set
-+# CONFIG_SCA3000 is not set
-+
-+#
-+# Analog to digital converters
-+#
-+# CONFIG_AD7291 is not set
-+# CONFIG_AD7606 is not set
-+# CONFIG_AD799X is not set
-+# CONFIG_AD7780 is not set
-+# CONFIG_AD7816 is not set
-+# CONFIG_AD7192 is not set
-+# CONFIG_ADT7410 is not set
-+# CONFIG_AD7280 is not set
-+CONFIG_MAX78M6610_LMU=m
-+
-+#
-+# Analog digital bi-direction converters
-+#
-+# CONFIG_ADT7316 is not set
-+
-+#
-+# Capacitance to digital converters
-+#
-+# CONFIG_AD7150 is not set
-+# CONFIG_AD7152 is not set
-+# CONFIG_AD7746 is not set
-+
-+#
-+# Direct Digital Synthesis
-+#
-+# CONFIG_AD5930 is not set
-+# CONFIG_AD9832 is not set
-+# CONFIG_AD9834 is not set
-+# CONFIG_AD9850 is not set
-+# CONFIG_AD9852 is not set
-+# CONFIG_AD9910 is not set
-+# CONFIG_AD9951 is not set
-+
-+#
-+# Digital gyroscope sensors
-+#
-+# CONFIG_ADIS16060 is not set
-+# CONFIG_ADIS16080 is not set
-+# CONFIG_ADIS16130 is not set
-+# CONFIG_ADIS16260 is not set
-+# CONFIG_ADXRS450 is not set
-+
-+#
-+# Network Analyzer, Impedance Converters
-+#
-+# CONFIG_AD5933 is not set
-+
-+#
-+# Inertial measurement units
-+#
-+# CONFIG_ADIS16400 is not set
-+
-+#
-+# Light sensors
-+#
-+# CONFIG_SENSORS_ISL29018 is not set
-+# CONFIG_SENSORS_ISL29028 is not set
-+# CONFIG_SENSORS_TSL2563 is not set
-+# CONFIG_TSL2583 is not set
-+# CONFIG_TSL2x7x is not set
-+
-+#
-+# Magnetometer sensors
-+#
-+# CONFIG_SENSORS_AK8975 is not set
-+# CONFIG_SENSORS_HMC5843 is not set
-+
-+#
-+# Active energy metering IC
-+#
-+# CONFIG_ADE7753 is not set
-+# CONFIG_ADE7754 is not set
-+# CONFIG_ADE7758 is not set
-+# CONFIG_ADE7759 is not set
-+# CONFIG_ADE7854 is not set
-+
-+#
-+# Resolver to digital converters
-+#
-+# CONFIG_AD2S90 is not set
-+# CONFIG_AD2S1200 is not set
-+# CONFIG_AD2S1210 is not set
-+
-+#
-+# Triggers - standalone
-+#
-+# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set
-+# CONFIG_IIO_GPIO_TRIGGER is not set
-+CONFIG_IIO_SYSFS_TRIGGER=m
-+CONFIG_IIO_HRTIMER_TRIGGER=m
-+# CONFIG_IIO_SIMPLE_DUMMY is not set
-+# CONFIG_ZSMALLOC is not set
-+# CONFIG_CRYSTALHD is not set
-+# CONFIG_ACPI_QUICKSTART is not set
-+# CONFIG_USB_ENESTORAGE is not set
-+# CONFIG_BCM_WIMAX is not set
-+# CONFIG_FT1000 is not set
-+
-+#
-+# Speakup console speech
-+#
-+# CONFIG_SPEAKUP is not set
-+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
-+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
-+# CONFIG_STAGING_MEDIA is not set
-+
-+#
-+# Android
-+#
-+# CONFIG_ANDROID is not set
-+# CONFIG_USB_WPAN_HCD is not set
-+# CONFIG_WIMAX_GDM72XX is not set
-+# CONFIG_CSR_WIFI is not set
-+# CONFIG_NET_VENDOR_SILICOM is not set
-+# CONFIG_CED1401 is not set
-+# CONFIG_DGRP is not set
-+# CONFIG_SB105X is not set
-+CONFIG_X86_PLATFORM_DEVICES=y
-+# CONFIG_ACERHDF is not set
-+# CONFIG_ASUS_LAPTOP is not set
-+# CONFIG_FUJITSU_TABLET is not set
-+# CONFIG_AMILO_RFKILL is not set
-+# CONFIG_HP_ACCEL is not set
-+# CONFIG_SONY_LAPTOP is not set
-+# CONFIG_THINKPAD_ACPI is not set
-+# CONFIG_SENSORS_HDAPS is not set
-+# CONFIG_INTEL_MENLOW is not set
-+# CONFIG_ACPI_WMI is not set
-+# CONFIG_TOPSTAR_LAPTOP is not set
-+# CONFIG_TOSHIBA_BT_RFKILL is not set
-+# CONFIG_ACPI_CMPC is not set
-+CONFIG_INTEL_CLN_ESRAM=y
-+CONFIG_INTEL_CLN_ECC_REFRESH_PERIOD=24
-+CONFIG_INTEL_CLN_THERMAL=y
-+CONFIG_INTEL_CLN_AUDIO_CTRL=m
-+# CONFIG_INTEL_IPS is not set
-+# CONFIG_IBM_RTL is not set
-+# CONFIG_XO15_EBOOK is not set
-+
-+#
-+# Hardware Spinlock drivers
-+#
-+CONFIG_CLKSRC_I8253=y
-+CONFIG_CLKEVT_I8253=y
-+CONFIG_CLKBLD_I8253=y
-+# CONFIG_IOMMU_SUPPORT is not set
-+
-+#
-+# Remoteproc drivers (EXPERIMENTAL)
-+#
-+# CONFIG_STE_MODEM_RPROC is not set
-+
-+#
-+# Rpmsg drivers (EXPERIMENTAL)
-+#
-+# CONFIG_VIRT_DRIVERS is not set
-+# CONFIG_PM_DEVFREQ is not set
-+# CONFIG_EXTCON is not set
-+# CONFIG_MEMORY is not set
-+CONFIG_IIO=m
-+CONFIG_IIO_BUFFER=y
-+CONFIG_IIO_BUFFER_CB=y
-+CONFIG_IIO_KFIFO_BUF=m
-+CONFIG_IIO_TRIGGERED_BUFFER=m
-+CONFIG_IIO_TRIGGER=y
-+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
-+
-+#
-+# Accelerometers
-+#
-+CONFIG_IIO_LIS331DLH_INTEL_CLN=m
-+
-+#
-+# Analog to digital converters
-+#
-+# CONFIG_AD7266 is not set
-+CONFIG_AD7298=m
-+# CONFIG_AD7791 is not set
-+# CONFIG_AD7793 is not set
-+# CONFIG_AD7476 is not set
-+# CONFIG_AD7887 is not set
-+# CONFIG_MAX1363 is not set
-+# CONFIG_TI_ADC081C is not set
-+
-+#
-+# Amplifiers
-+#
-+# CONFIG_AD8366 is not set
-+
-+#
-+# Hid Sensor IIO Common
-+#
-+CONFIG_IIO_ST_SENSORS_I2C=m
-+CONFIG_IIO_ST_SENSORS_SPI=m
-+CONFIG_IIO_ST_SENSORS_CORE=m
-+
-+#
-+# Digital to analog converters
-+#
-+# CONFIG_AD5064 is not set
-+# CONFIG_AD5360 is not set
-+# CONFIG_AD5380 is not set
-+# CONFIG_AD5421 is not set
-+# CONFIG_AD5624R_SPI is not set
-+# CONFIG_AD5446 is not set
-+# CONFIG_AD5449 is not set
-+# CONFIG_AD5504 is not set
-+# CONFIG_AD5755 is not set
-+# CONFIG_AD5764 is not set
-+# CONFIG_AD5791 is not set
-+# CONFIG_AD5686 is not set
-+# CONFIG_MAX517 is not set
-+# CONFIG_MCP4725 is not set
-+
-+#
-+# Frequency Synthesizers DDS/PLL
-+#
-+
-+#
-+# Clock Generator/Distribution
-+#
-+# CONFIG_AD9523 is not set
-+
-+#
-+# Phase-Locked Loop (PLL) frequency synthesizers
-+#
-+# CONFIG_ADF4350 is not set
-+
-+#
-+# Digital gyroscope sensors
-+#
-+# CONFIG_ADIS16136 is not set
-+
-+#
-+# Inertial measurement units
-+#
-+# CONFIG_ADIS16480 is not set
-+
-+#
-+# Light sensors
-+#
-+# CONFIG_ADJD_S311 is not set
-+# CONFIG_VCNL4000 is not set
-+
-+#
-+# Magnetometer sensors
-+#
-+# CONFIG_VME_BUS is not set
-+CONFIG_PWM=y
-+CONFIG_PWM_SYSFS=y
-+# CONFIG_IPACK_BUS is not set
-+
-+#
-+# Firmware Drivers
-+#
-+# CONFIG_EDD is not set
-+CONFIG_FIRMWARE_MEMMAP=y
-+CONFIG_EFI_VARS=m
-+# CONFIG_DELL_RBU is not set
-+# CONFIG_DCDBAS is not set
-+CONFIG_DMIID=y
-+CONFIG_DMI_SYSFS=y
-+# CONFIG_ISCSI_IBFT_FIND is not set
-+# CONFIG_GOOGLE_FIRMWARE is not set
-+
-+#
-+# File systems
-+#
-+CONFIG_DCACHE_WORD_ACCESS=y
-+CONFIG_EXT2_FS=y
-+# CONFIG_EXT2_FS_XATTR is not set
-+# CONFIG_EXT2_FS_XIP is not set
-+CONFIG_EXT3_FS=y
-+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-+CONFIG_EXT3_FS_XATTR=y
-+CONFIG_EXT3_FS_POSIX_ACL=y
-+CONFIG_EXT3_FS_SECURITY=y
-+# CONFIG_EXT4_FS is not set
-+CONFIG_JBD=y
-+# CONFIG_JBD_DEBUG is not set
-+CONFIG_FS_MBCACHE=y
-+# CONFIG_REISERFS_FS is not set
-+# CONFIG_JFS_FS is not set
-+# CONFIG_XFS_FS is not set
-+# CONFIG_BTRFS_FS is not set
-+# CONFIG_NILFS2_FS is not set
-+CONFIG_FS_POSIX_ACL=y
-+CONFIG_FILE_LOCKING=y
-+CONFIG_FSNOTIFY=y
-+CONFIG_DNOTIFY=y
-+CONFIG_INOTIFY_USER=y
-+# CONFIG_FANOTIFY is not set
-+# CONFIG_QUOTA is not set
-+# CONFIG_QUOTACTL is not set
-+# CONFIG_AUTOFS4_FS is not set
-+# CONFIG_FUSE_FS is not set
-+CONFIG_GENERIC_ACL=y
-+
-+#
-+# Caches
-+#
-+# CONFIG_FSCACHE is not set
-+
-+#
-+# CD-ROM/DVD Filesystems
-+#
-+# CONFIG_ISO9660_FS is not set
-+# CONFIG_UDF_FS is not set
-+
-+#
-+# DOS/FAT/NT Filesystems
-+#
-+CONFIG_FAT_FS=y
-+# CONFIG_MSDOS_FS is not set
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_CODEPAGE=437
-+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-+# CONFIG_NTFS_FS is not set
-+
-+#
-+# Pseudo filesystems
-+#
-+CONFIG_PROC_FS=y
-+CONFIG_PROC_KCORE=y
-+CONFIG_PROC_SYSCTL=y
-+CONFIG_PROC_PAGE_MONITOR=y
-+CONFIG_SYSFS=y
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_TMPFS_XATTR=y
-+CONFIG_HUGETLBFS=y
-+CONFIG_HUGETLB_PAGE=y
-+# CONFIG_CONFIGFS_FS is not set
-+# CONFIG_MISC_FILESYSTEMS is not set
-+CONFIG_NETWORK_FILESYSTEMS=y
-+# CONFIG_NFS_FS is not set
-+# CONFIG_NFSD is not set
-+# CONFIG_CEPH_FS is not set
-+# CONFIG_CIFS is not set
-+# CONFIG_NCP_FS is not set
-+# CONFIG_CODA_FS is not set
-+# CONFIG_AFS_FS is not set
-+CONFIG_NLS=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+# CONFIG_NLS_CODEPAGE_737 is not set
-+# CONFIG_NLS_CODEPAGE_775 is not set
-+CONFIG_NLS_CODEPAGE_850=y
-+# CONFIG_NLS_CODEPAGE_852 is not set
-+# CONFIG_NLS_CODEPAGE_855 is not set
-+# CONFIG_NLS_CODEPAGE_857 is not set
-+# CONFIG_NLS_CODEPAGE_860 is not set
-+# CONFIG_NLS_CODEPAGE_861 is not set
-+# CONFIG_NLS_CODEPAGE_862 is not set
-+# CONFIG_NLS_CODEPAGE_863 is not set
-+# CONFIG_NLS_CODEPAGE_864 is not set
-+# CONFIG_NLS_CODEPAGE_865 is not set
-+# CONFIG_NLS_CODEPAGE_866 is not set
-+# CONFIG_NLS_CODEPAGE_869 is not set
-+# CONFIG_NLS_CODEPAGE_936 is not set
-+# CONFIG_NLS_CODEPAGE_950 is not set
-+# CONFIG_NLS_CODEPAGE_932 is not set
-+# CONFIG_NLS_CODEPAGE_949 is not set
-+# CONFIG_NLS_CODEPAGE_874 is not set
-+# CONFIG_NLS_ISO8859_8 is not set
-+# CONFIG_NLS_CODEPAGE_1250 is not set
-+# CONFIG_NLS_CODEPAGE_1251 is not set
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=y
-+# CONFIG_NLS_ISO8859_2 is not set
-+# CONFIG_NLS_ISO8859_3 is not set
-+# CONFIG_NLS_ISO8859_4 is not set
-+# CONFIG_NLS_ISO8859_5 is not set
-+# CONFIG_NLS_ISO8859_6 is not set
-+# CONFIG_NLS_ISO8859_7 is not set
-+# CONFIG_NLS_ISO8859_9 is not set
-+# CONFIG_NLS_ISO8859_13 is not set
-+# CONFIG_NLS_ISO8859_14 is not set
-+# CONFIG_NLS_ISO8859_15 is not set
-+# CONFIG_NLS_KOI8_R is not set
-+# CONFIG_NLS_KOI8_U is not set
-+# CONFIG_NLS_MAC_ROMAN is not set
-+# CONFIG_NLS_MAC_CELTIC is not set
-+# CONFIG_NLS_MAC_CENTEURO is not set
-+# CONFIG_NLS_MAC_CROATIAN is not set
-+# CONFIG_NLS_MAC_CYRILLIC is not set
-+# CONFIG_NLS_MAC_GAELIC is not set
-+# CONFIG_NLS_MAC_GREEK is not set
-+# CONFIG_NLS_MAC_ICELAND is not set
-+# CONFIG_NLS_MAC_INUIT is not set
-+# CONFIG_NLS_MAC_ROMANIAN is not set
-+# CONFIG_NLS_MAC_TURKISH is not set
-+# CONFIG_NLS_UTF8 is not set
-+
-+#
-+# Kernel hacking
-+#
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-+CONFIG_PRINTK_TIME=y
-+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
-+# CONFIG_ENABLE_WARN_DEPRECATED is not set
-+CONFIG_ENABLE_MUST_CHECK=y
-+CONFIG_FRAME_WARN=2048
-+CONFIG_MAGIC_SYSRQ=y
-+# CONFIG_STRIP_ASM_SYMS is not set
-+# CONFIG_READABLE_ASM is not set
-+# CONFIG_UNUSED_SYMBOLS is not set
-+CONFIG_DEBUG_FS=y
-+CONFIG_HEADERS_CHECK=y
-+# CONFIG_DEBUG_SECTION_MISMATCH is not set
-+CONFIG_DEBUG_KERNEL=y
-+# CONFIG_DEBUG_SHIRQ is not set
-+# CONFIG_LOCKUP_DETECTOR is not set
-+# CONFIG_PANIC_ON_OOPS is not set
-+CONFIG_PANIC_ON_OOPS_VALUE=0
-+# CONFIG_DETECT_HUNG_TASK is not set
-+# CONFIG_SCHED_DEBUG is not set
-+# CONFIG_SCHEDSTATS is not set
-+CONFIG_TIMER_STATS=y
-+# CONFIG_DEBUG_OBJECTS is not set
-+# CONFIG_SLUB_DEBUG_ON is not set
-+# CONFIG_SLUB_STATS is not set
-+CONFIG_HAVE_DEBUG_KMEMLEAK=y
-+# CONFIG_DEBUG_KMEMLEAK is not set
-+# CONFIG_DEBUG_RT_MUTEXES is not set
-+# CONFIG_RT_MUTEX_TESTER is not set
-+# CONFIG_DEBUG_SPINLOCK is not set
-+# CONFIG_DEBUG_MUTEXES is not set
-+# CONFIG_DEBUG_LOCK_ALLOC is not set
-+# CONFIG_PROVE_LOCKING is not set
-+# CONFIG_SPARSE_RCU_POINTER is not set
-+# CONFIG_LOCK_STAT is not set
-+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
-+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-+# CONFIG_DEBUG_STACK_USAGE is not set
-+# CONFIG_DEBUG_KOBJECT is not set
-+# CONFIG_DEBUG_HIGHMEM is not set
-+CONFIG_DEBUG_BUGVERBOSE=y
-+# CONFIG_DEBUG_INFO is not set
-+# CONFIG_DEBUG_VM is not set
-+# CONFIG_DEBUG_VIRTUAL is not set
-+# CONFIG_DEBUG_WRITECOUNT is not set
-+CONFIG_DEBUG_MEMORY_INIT=y
-+# CONFIG_DEBUG_LIST is not set
-+# CONFIG_TEST_LIST_SORT is not set
-+# CONFIG_DEBUG_SG is not set
-+# CONFIG_DEBUG_NOTIFIERS is not set
-+# CONFIG_DEBUG_CREDENTIALS is not set
-+CONFIG_ARCH_WANT_FRAME_POINTERS=y
-+CONFIG_FRAME_POINTER=y
-+# CONFIG_BOOT_PRINTK_DELAY is not set
-+# CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_RCU_TRACE is not set
-+# CONFIG_BACKTRACE_SELF_TEST is not set
-+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
-+# CONFIG_LKDTM is not set
-+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
-+# CONFIG_FAULT_INJECTION is not set
-+# CONFIG_LATENCYTOP is not set
-+# CONFIG_DEBUG_PAGEALLOC is not set
-+CONFIG_USER_STACKTRACE_SUPPORT=y
-+CONFIG_HAVE_FUNCTION_TRACER=y
-+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
-+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-+CONFIG_HAVE_DYNAMIC_FTRACE=y
-+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
-+CONFIG_HAVE_C_RECORDMCOUNT=y
-+CONFIG_TRACING_SUPPORT=y
-+# CONFIG_FTRACE is not set
-+# CONFIG_RBTREE_TEST is not set
-+# CONFIG_INTERVAL_TREE_TEST is not set
-+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
-+# CONFIG_BUILD_DOCSRC is not set
-+# CONFIG_DYNAMIC_DEBUG is not set
-+# CONFIG_DMA_API_DEBUG is not set
-+# CONFIG_ATOMIC64_SELFTEST is not set
-+# CONFIG_SAMPLES is not set
-+CONFIG_HAVE_ARCH_KGDB=y
-+# CONFIG_KGDB is not set
-+CONFIG_HAVE_ARCH_KMEMCHECK=y
-+# CONFIG_KMEMCHECK is not set
-+# CONFIG_TEST_KSTRTOX is not set
-+# CONFIG_STRICT_DEVMEM is not set
-+CONFIG_X86_VERBOSE_BOOTUP=y
-+CONFIG_EARLY_PRINTK=y
-+# CONFIG_EARLY_PRINTK_DBGP is not set
-+CONFIG_DEBUG_STACKOVERFLOW=y
-+CONFIG_X86_PTDUMP=y
-+CONFIG_DEBUG_RODATA=y
-+# CONFIG_DEBUG_RODATA_TEST is not set
-+CONFIG_DEBUG_SET_MODULE_RONX=y
-+# CONFIG_DEBUG_NX_TEST is not set
-+# CONFIG_DOUBLEFAULT is not set
-+# CONFIG_IOMMU_STRESS is not set
-+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
-+CONFIG_IO_DELAY_TYPE_0X80=0
-+CONFIG_IO_DELAY_TYPE_0XED=1
-+CONFIG_IO_DELAY_TYPE_UDELAY=2
-+CONFIG_IO_DELAY_TYPE_NONE=3
-+CONFIG_IO_DELAY_0X80=y
-+# CONFIG_IO_DELAY_0XED is not set
-+# CONFIG_IO_DELAY_UDELAY is not set
-+# CONFIG_IO_DELAY_NONE is not set
-+CONFIG_DEFAULT_IO_DELAY_TYPE=0
-+CONFIG_DEBUG_BOOT_PARAMS=y
-+# CONFIG_CPA_DEBUG is not set
-+CONFIG_OPTIMIZE_INLINING=y
-+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
-+# CONFIG_DEBUG_NMI_SELFTEST is not set
-+
-+#
-+# Security options
-+#
-+CONFIG_KEYS=y
-+# CONFIG_ENCRYPTED_KEYS is not set
-+CONFIG_KEYS_DEBUG_PROC_KEYS=y
-+# CONFIG_SECURITY_DMESG_RESTRICT is not set
-+CONFIG_SECURITY=y
-+# CONFIG_SECURITYFS is not set
-+CONFIG_SECURITY_NETWORK=y
-+# CONFIG_SECURITY_NETWORK_XFRM is not set
-+# CONFIG_SECURITY_PATH is not set
-+# CONFIG_SECURITY_SMACK is not set
-+# CONFIG_SECURITY_TOMOYO is not set
-+# CONFIG_SECURITY_APPARMOR is not set
-+# CONFIG_SECURITY_YAMA is not set
-+# CONFIG_IMA is not set
-+# CONFIG_EVM is not set
-+CONFIG_DEFAULT_SECURITY_DAC=y
-+CONFIG_DEFAULT_SECURITY=""
-+CONFIG_CRYPTO=y
-+
-+#
-+# Crypto core or helper
-+#
-+CONFIG_CRYPTO_ALGAPI=y
-+CONFIG_CRYPTO_ALGAPI2=y
-+CONFIG_CRYPTO_AEAD2=y
-+CONFIG_CRYPTO_BLKCIPHER=m
-+CONFIG_CRYPTO_BLKCIPHER2=y
-+CONFIG_CRYPTO_HASH=y
-+CONFIG_CRYPTO_HASH2=y
-+CONFIG_CRYPTO_RNG=m
-+CONFIG_CRYPTO_RNG2=y
-+CONFIG_CRYPTO_PCOMP2=y
-+CONFIG_CRYPTO_MANAGER=m
-+CONFIG_CRYPTO_MANAGER2=y
-+# CONFIG_CRYPTO_USER is not set
-+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-+# CONFIG_CRYPTO_GF128MUL is not set
-+# CONFIG_CRYPTO_NULL is not set
-+CONFIG_CRYPTO_WORKQUEUE=y
-+# CONFIG_CRYPTO_CRYPTD is not set
-+# CONFIG_CRYPTO_AUTHENC is not set
-+# CONFIG_CRYPTO_TEST is not set
-+
-+#
-+# Authenticated Encryption with Associated Data
-+#
-+# CONFIG_CRYPTO_CCM is not set
-+# CONFIG_CRYPTO_GCM is not set
-+# CONFIG_CRYPTO_SEQIV is not set
-+
-+#
-+# Block modes
-+#
-+# CONFIG_CRYPTO_CBC is not set
-+# CONFIG_CRYPTO_CTR is not set
-+# CONFIG_CRYPTO_CTS is not set
-+CONFIG_CRYPTO_ECB=m
-+# CONFIG_CRYPTO_LRW is not set
-+# CONFIG_CRYPTO_PCBC is not set
-+# CONFIG_CRYPTO_XTS is not set
-+
-+#
-+# Hash modes
-+#
-+# CONFIG_CRYPTO_HMAC is not set
-+# CONFIG_CRYPTO_XCBC is not set
-+# CONFIG_CRYPTO_VMAC is not set
-+
-+#
-+# Digest
-+#
-+CONFIG_CRYPTO_CRC32C=y
-+# CONFIG_CRYPTO_CRC32C_INTEL is not set
-+# CONFIG_CRYPTO_GHASH is not set
-+# CONFIG_CRYPTO_MD4 is not set
-+# CONFIG_CRYPTO_MD5 is not set
-+# CONFIG_CRYPTO_MICHAEL_MIC is not set
-+# CONFIG_CRYPTO_RMD128 is not set
-+# CONFIG_CRYPTO_RMD160 is not set
-+# CONFIG_CRYPTO_RMD256 is not set
-+# CONFIG_CRYPTO_RMD320 is not set
-+# CONFIG_CRYPTO_SHA1 is not set
-+CONFIG_CRYPTO_SHA256=m
-+# CONFIG_CRYPTO_SHA512 is not set
-+# CONFIG_CRYPTO_TGR192 is not set
-+# CONFIG_CRYPTO_WP512 is not set
-+
-+#
-+# Ciphers
-+#
-+CONFIG_CRYPTO_AES=y
-+# CONFIG_CRYPTO_AES_586 is not set
-+# CONFIG_CRYPTO_AES_NI_INTEL is not set
-+# CONFIG_CRYPTO_ANUBIS is not set
-+CONFIG_CRYPTO_ARC4=m
-+# CONFIG_CRYPTO_BLOWFISH is not set
-+# CONFIG_CRYPTO_CAMELLIA is not set
-+# CONFIG_CRYPTO_CAST5 is not set
-+# CONFIG_CRYPTO_CAST6 is not set
-+# CONFIG_CRYPTO_DES is not set
-+# CONFIG_CRYPTO_FCRYPT is not set
-+# CONFIG_CRYPTO_KHAZAD is not set
-+# CONFIG_CRYPTO_SALSA20 is not set
-+# CONFIG_CRYPTO_SALSA20_586 is not set
-+# CONFIG_CRYPTO_SEED is not set
-+# CONFIG_CRYPTO_SERPENT is not set
-+# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
-+# CONFIG_CRYPTO_TEA is not set
-+# CONFIG_CRYPTO_TWOFISH is not set
-+# CONFIG_CRYPTO_TWOFISH_586 is not set
-+
-+#
-+# Compression
-+#
-+# CONFIG_CRYPTO_DEFLATE is not set
-+# CONFIG_CRYPTO_ZLIB is not set
-+# CONFIG_CRYPTO_LZO is not set
-+
-+#
-+# Random Number Generation
-+#
-+CONFIG_CRYPTO_ANSI_CPRNG=m
-+# CONFIG_CRYPTO_USER_API_HASH is not set
-+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-+CONFIG_CRYPTO_HW=y
-+# CONFIG_CRYPTO_DEV_PADLOCK is not set
-+# CONFIG_CRYPTO_DEV_GEODE is not set
-+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
-+CONFIG_HAVE_KVM=y
-+# CONFIG_VIRTUALIZATION is not set
-+# CONFIG_BINARY_PRINTF is not set
-+
-+#
-+# Library routines
-+#
-+CONFIG_BITREVERSE=y
-+CONFIG_GENERIC_STRNCPY_FROM_USER=y
-+CONFIG_GENERIC_STRNLEN_USER=y
-+CONFIG_GENERIC_FIND_FIRST_BIT=y
-+CONFIG_GENERIC_PCI_IOMAP=y
-+CONFIG_GENERIC_IOMAP=y
-+CONFIG_GENERIC_IO=y
-+CONFIG_PERCPU_RWSEM=y
-+CONFIG_CRC_CCITT=m
-+CONFIG_CRC16=y
-+CONFIG_CRC_T10DIF=y
-+# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC32=y
-+# CONFIG_CRC32_SELFTEST is not set
-+CONFIG_CRC32_SLICEBY8=y
-+# CONFIG_CRC32_SLICEBY4 is not set
-+# CONFIG_CRC32_SARWATE is not set
-+# CONFIG_CRC32_BIT is not set
-+# CONFIG_CRC7 is not set
-+# CONFIG_LIBCRC32C is not set
-+# CONFIG_CRC8 is not set
-+CONFIG_ZLIB_INFLATE=y
-+CONFIG_ZLIB_DEFLATE=m
-+# CONFIG_XZ_DEC is not set
-+# CONFIG_XZ_DEC_BCJ is not set
-+CONFIG_DECOMPRESS_GZIP=y
-+CONFIG_DECOMPRESS_BZIP2=y
-+CONFIG_DECOMPRESS_LZMA=y
-+CONFIG_HAS_IOMEM=y
-+CONFIG_HAS_IOPORT=y
-+CONFIG_HAS_DMA=y
-+CONFIG_DQL=y
-+CONFIG_NLATTR=y
-+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
-+CONFIG_AVERAGE=y
-+# CONFIG_CORDIC is not set
-+# CONFIG_DDR is not set
-diff --git a/meta/cfg/kernel-cache/bsp/clanton/clanton_emutex.cfg b/meta/cfg/kernel-cache/bsp/clanton/clanton_emutex.cfg
-new file mode 100644
-index 0000000..68c375e
---- /dev/null
-+++ b/meta/cfg/kernel-cache/bsp/clanton/clanton_emutex.cfg
-@@ -0,0 +1,2938 @@
-+#
-+# Automatically generated file; DO NOT EDIT.
-+# Linux/i386 3.8.7 Kernel Configuration
-+#
-+# CONFIG_64BIT is not set
-+CONFIG_X86_32=y
-+CONFIG_X86=y
-+CONFIG_INSTRUCTION_DECODER=y
-+CONFIG_OUTPUT_FORMAT="elf32-i386"
-+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
-+CONFIG_MMU=y
-+CONFIG_NEED_SG_DMA_LENGTH=y
-+CONFIG_GENERIC_ISA_DMA=y
-+CONFIG_GENERIC_BUG=y
-+CONFIG_GENERIC_HWEIGHT=y
-+CONFIG_GENERIC_GPIO=y
-+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-+CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_ARCH_HAS_CPU_RELAX=y
-+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
-+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
-+CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
-+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
-+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
-+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
-+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
-+CONFIG_ARCH_SUSPEND_POSSIBLE=y
-+# CONFIG_ZONE_DMA32 is not set
-+# CONFIG_AUDIT_ARCH is not set
-+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
-+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
-+CONFIG_X86_32_LAZY_GS=y
-+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
-+CONFIG_ARCH_SUPPORTS_UPROBES=y
-+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-+CONFIG_HAVE_IRQ_WORK=y
-+CONFIG_IRQ_WORK=y
-+CONFIG_BUILDTIME_EXTABLE_SORT=y
-+
-+#
-+# General setup
-+#
-+CONFIG_EXPERIMENTAL=y
-+CONFIG_BROKEN_ON_SMP=y
-+CONFIG_INIT_ENV_ARG_LIMIT=32
-+CONFIG_CROSS_COMPILE=""
-+CONFIG_LOCALVERSION=""
-+# CONFIG_LOCALVERSION_AUTO is not set
-+CONFIG_HAVE_KERNEL_GZIP=y
-+CONFIG_HAVE_KERNEL_BZIP2=y
-+CONFIG_HAVE_KERNEL_LZMA=y
-+CONFIG_HAVE_KERNEL_XZ=y
-+CONFIG_HAVE_KERNEL_LZO=y
-+# CONFIG_KERNEL_GZIP is not set
-+# CONFIG_KERNEL_BZIP2 is not set
-+CONFIG_KERNEL_LZMA=y
-+# CONFIG_KERNEL_XZ is not set
-+# CONFIG_KERNEL_LZO is not set
-+CONFIG_DEFAULT_HOSTNAME="(none)"
-+# CONFIG_SWAP is not set
-+CONFIG_SYSVIPC=y
-+CONFIG_SYSVIPC_SYSCTL=y
-+CONFIG_POSIX_MQUEUE=y
-+CONFIG_POSIX_MQUEUE_SYSCTL=y
-+# CONFIG_FHANDLE is not set
-+# CONFIG_AUDIT is not set
-+CONFIG_HAVE_GENERIC_HARDIRQS=y
-+
-+#
-+# IRQ subsystem
-+#
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_GENERIC_IRQ_SHOW=y
-+CONFIG_GENERIC_IRQ_CHIP=y
-+CONFIG_IRQ_DOMAIN=y
-+# CONFIG_IRQ_DOMAIN_DEBUG is not set
-+CONFIG_IRQ_FORCED_THREADING=y
-+CONFIG_SPARSE_IRQ=y
-+CONFIG_CLOCKSOURCE_WATCHDOG=y
-+CONFIG_KTIME_SCALAR=y
-+CONFIG_GENERIC_CLOCKEVENTS=y
-+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
-+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
-+CONFIG_GENERIC_CMOS_UPDATE=y
-+
-+#
-+# Timers subsystem
-+#
-+CONFIG_TICK_ONESHOT=y
-+CONFIG_NO_HZ=y
-+CONFIG_HIGH_RES_TIMERS=y
-+
-+#
-+# CPU/Task time and stats accounting
-+#
-+CONFIG_TICK_CPU_ACCOUNTING=y
-+# CONFIG_IRQ_TIME_ACCOUNTING is not set
-+CONFIG_BSD_PROCESS_ACCT=y
-+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-+# CONFIG_TASKSTATS is not set
-+
-+#
-+# RCU Subsystem
-+#
-+CONFIG_TINY_RCU=y
-+# CONFIG_PREEMPT_RCU is not set
-+# CONFIG_TREE_RCU_TRACE is not set
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
-+CONFIG_LOG_BUF_SHIFT=18
-+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
-+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
-+CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
-+CONFIG_CGROUPS=y
-+# CONFIG_CGROUP_DEBUG is not set
-+CONFIG_CGROUP_FREEZER=y
-+# CONFIG_CGROUP_DEVICE is not set
-+CONFIG_CPUSETS=y
-+CONFIG_PROC_PID_CPUSET=y
-+CONFIG_CGROUP_CPUACCT=y
-+CONFIG_RESOURCE_COUNTERS=y
-+# CONFIG_MEMCG is not set
-+# CONFIG_CGROUP_HUGETLB is not set
-+# CONFIG_CGROUP_PERF is not set
-+CONFIG_CGROUP_SCHED=y
-+CONFIG_FAIR_GROUP_SCHED=y
-+# CONFIG_CFS_BANDWIDTH is not set
-+# CONFIG_RT_GROUP_SCHED is not set
-+# CONFIG_BLK_CGROUP is not set
-+# CONFIG_CHECKPOINT_RESTORE is not set
-+CONFIG_NAMESPACES=y
-+CONFIG_UTS_NS=y
-+CONFIG_IPC_NS=y
-+# CONFIG_USER_NS is not set
-+CONFIG_PID_NS=y
-+CONFIG_NET_NS=y
-+CONFIG_UIDGID_CONVERTED=y
-+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
-+# CONFIG_SCHED_AUTOGROUP is not set
-+# CONFIG_SYSFS_DEPRECATED is not set
-+CONFIG_RELAY=y
-+CONFIG_BLK_DEV_INITRD=y
-+CONFIG_INITRAMFS_SOURCE=""
-+CONFIG_RD_GZIP=y
-+CONFIG_RD_BZIP2=y
-+CONFIG_RD_LZMA=y
-+# CONFIG_RD_XZ is not set
-+# CONFIG_RD_LZO is not set
-+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-+CONFIG_SYSCTL=y
-+CONFIG_ANON_INODES=y
-+CONFIG_EXPERT=y
-+CONFIG_HAVE_UID16=y
-+CONFIG_UID16=y
-+CONFIG_SYSCTL_SYSCALL=y
-+CONFIG_SYSCTL_EXCEPTION_TRACE=y
-+CONFIG_KALLSYMS=y
-+CONFIG_KALLSYMS_ALL=y
-+CONFIG_HOTPLUG=y
-+CONFIG_PRINTK=y
-+CONFIG_BUG=y
-+CONFIG_ELF_CORE=y
-+# CONFIG_PCSPKR_PLATFORM is not set
-+CONFIG_HAVE_PCSPKR_PLATFORM=y
-+CONFIG_BASE_FULL=y
-+CONFIG_FUTEX=y
-+CONFIG_EPOLL=y
-+CONFIG_SIGNALFD=y
-+CONFIG_TIMERFD=y
-+CONFIG_EVENTFD=y
-+CONFIG_SHMEM=y
-+CONFIG_AIO=y
-+CONFIG_EMBEDDED=y
-+CONFIG_HAVE_PERF_EVENTS=y
-+
-+#
-+# Kernel Performance Events And Counters
-+#
-+CONFIG_PERF_EVENTS=y
-+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
-+CONFIG_VM_EVENT_COUNTERS=y
-+CONFIG_PCI_QUIRKS=y
-+CONFIG_SLUB_DEBUG=y
-+# CONFIG_COMPAT_BRK is not set
-+# CONFIG_SLAB is not set
-+CONFIG_SLUB=y
-+# CONFIG_SLOB is not set
-+# CONFIG_PROFILING is not set
-+CONFIG_HAVE_OPROFILE=y
-+CONFIG_OPROFILE_NMI_TIMER=y
-+# CONFIG_KPROBES is not set
-+CONFIG_JUMP_LABEL=y
-+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
-+CONFIG_HAVE_IOREMAP_PROT=y
-+CONFIG_HAVE_KPROBES=y
-+CONFIG_HAVE_KRETPROBES=y
-+CONFIG_HAVE_OPTPROBES=y
-+CONFIG_HAVE_ARCH_TRACEHOOK=y
-+CONFIG_HAVE_DMA_ATTRS=y
-+CONFIG_HAVE_DMA_CONTIGUOUS=y
-+CONFIG_GENERIC_SMP_IDLE_THREAD=y
-+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
-+CONFIG_HAVE_DMA_API_DEBUG=y
-+CONFIG_HAVE_HW_BREAKPOINT=y
-+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
-+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
-+CONFIG_HAVE_PERF_EVENTS_NMI=y
-+CONFIG_HAVE_PERF_REGS=y
-+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
-+CONFIG_HAVE_ARCH_JUMP_LABEL=y
-+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
-+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
-+CONFIG_HAVE_CMPXCHG_LOCAL=y
-+CONFIG_HAVE_CMPXCHG_DOUBLE=y
-+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
-+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
-+CONFIG_SECCOMP_FILTER=y
-+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
-+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
-+CONFIG_MODULES_USE_ELF_REL=y
-+CONFIG_GENERIC_SIGALTSTACK=y
-+CONFIG_CLONE_BACKWARDS=y
-+
-+#
-+# GCOV-based kernel profiling
-+#
-+# CONFIG_GCOV_KERNEL is not set
-+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-+CONFIG_SLABINFO=y
-+CONFIG_RT_MUTEXES=y
-+CONFIG_BASE_SMALL=0
-+CONFIG_MODULES=y
-+# CONFIG_MODULE_FORCE_LOAD is not set
-+CONFIG_MODULE_UNLOAD=y
-+# CONFIG_MODULE_FORCE_UNLOAD is not set
-+# CONFIG_MODVERSIONS is not set
-+# CONFIG_MODULE_SRCVERSION_ALL is not set
-+# CONFIG_MODULE_SIG is not set
-+CONFIG_BLOCK=y
-+# CONFIG_LBDAF is not set
-+CONFIG_BLK_DEV_BSG=y
-+# CONFIG_BLK_DEV_BSGLIB is not set
-+# CONFIG_BLK_DEV_INTEGRITY is not set
-+
-+#
-+# Partition Types
-+#
-+CONFIG_PARTITION_ADVANCED=y
-+# CONFIG_ACORN_PARTITION is not set
-+# CONFIG_OSF_PARTITION is not set
-+# CONFIG_AMIGA_PARTITION is not set
-+# CONFIG_ATARI_PARTITION is not set
-+# CONFIG_MAC_PARTITION is not set
-+CONFIG_MSDOS_PARTITION=y
-+CONFIG_BSD_DISKLABEL=y
-+# CONFIG_MINIX_SUBPARTITION is not set
-+# CONFIG_SOLARIS_X86_PARTITION is not set
-+# CONFIG_UNIXWARE_DISKLABEL is not set
-+# CONFIG_LDM_PARTITION is not set
-+# CONFIG_SGI_PARTITION is not set
-+# CONFIG_ULTRIX_PARTITION is not set
-+# CONFIG_SUN_PARTITION is not set
-+# CONFIG_KARMA_PARTITION is not set
-+# CONFIG_EFI_PARTITION is not set
-+# CONFIG_SYSV68_PARTITION is not set
-+
-+#
-+# IO Schedulers
-+#
-+CONFIG_IOSCHED_NOOP=y
-+CONFIG_IOSCHED_DEADLINE=y
-+CONFIG_IOSCHED_CFQ=y
-+# CONFIG_DEFAULT_DEADLINE is not set
-+CONFIG_DEFAULT_CFQ=y
-+# CONFIG_DEFAULT_NOOP is not set
-+CONFIG_DEFAULT_IOSCHED="cfq"
-+CONFIG_UNINLINE_SPIN_UNLOCK=y
-+CONFIG_FREEZER=y
-+
-+#
-+# Processor type and features
-+#
-+# CONFIG_ZONE_DMA is not set
-+# CONFIG_SMP is not set
-+CONFIG_X86_MPPARSE=y
-+CONFIG_X86_EXTENDED_PLATFORM=y
-+CONFIG_INTEL_QUARK_X1000_SOC=y
-+# CONFIG_X86_WANT_INTEL_MID is not set
-+# CONFIG_X86_RDC321X is not set
-+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
-+
-+#
-+# Intel Media SOC Gen3 support
-+#
-+CONFIG_ARCH_GEN3=y
-+# CONFIG_X86_32_IRIS is not set
-+CONFIG_SCHED_OMIT_FRAME_POINTER=y
-+# CONFIG_PARAVIRT_GUEST is not set
-+CONFIG_NO_BOOTMEM=y
-+# CONFIG_MEMTEST is not set
-+# CONFIG_M486 is not set
-+# CONFIG_M586 is not set
-+CONFIG_M586TSC=y
-+# CONFIG_M586MMX is not set
-+# CONFIG_M686 is not set
-+# CONFIG_MPENTIUMII is not set
-+# CONFIG_MPENTIUMIII is not set
-+# CONFIG_MPENTIUMM is not set
-+# CONFIG_MPENTIUM4 is not set
-+# CONFIG_MK6 is not set
-+# CONFIG_MK7 is not set
-+# CONFIG_MK8 is not set
-+# CONFIG_MCRUSOE is not set
-+# CONFIG_MEFFICEON is not set
-+# CONFIG_MWINCHIPC6 is not set
-+# CONFIG_MWINCHIP3D is not set
-+# CONFIG_MELAN is not set
-+# CONFIG_MGEODEGX1 is not set
-+# CONFIG_MGEODE_LX is not set
-+# CONFIG_MCYRIXIII is not set
-+# CONFIG_MVIAC3_2 is not set
-+# CONFIG_MVIAC7 is not set
-+# CONFIG_MCORE2 is not set
-+# CONFIG_MATOM is not set
-+CONFIG_X86_GENERIC=y
-+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
-+CONFIG_X86_L1_CACHE_SHIFT=6
-+# CONFIG_X86_PPRO_FENCE is not set
-+CONFIG_X86_F00F_BUG=y
-+CONFIG_X86_ALIGNMENT_16=y
-+CONFIG_X86_INTEL_USERCOPY=y
-+CONFIG_X86_TSC=y
-+CONFIG_X86_CMPXCHG64=y
-+CONFIG_X86_MINIMUM_CPU_FAMILY=5
-+# CONFIG_PROCESSOR_SELECT is not set
-+CONFIG_CPU_SUP_INTEL=y
-+CONFIG_CPU_SUP_CYRIX_32=y
-+CONFIG_CPU_SUP_AMD=y
-+CONFIG_CPU_SUP_CENTAUR=y
-+CONFIG_CPU_SUP_TRANSMETA_32=y
-+CONFIG_CPU_SUP_UMC_32=y
-+CONFIG_HPET_TIMER=y
-+CONFIG_HPET_EMULATE_RTC=y
-+# CONFIG_DMI is not set
-+CONFIG_NR_CPUS=1
-+# CONFIG_PREEMPT_NONE is not set
-+CONFIG_PREEMPT_VOLUNTARY=y
-+# CONFIG_PREEMPT is not set
-+CONFIG_X86_UP_APIC=y
-+CONFIG_X86_UP_IOAPIC=y
-+CONFIG_X86_LOCAL_APIC=y
-+CONFIG_X86_IO_APIC=y
-+# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
-+CONFIG_X86_MCE=y
-+CONFIG_X86_MCE_INTEL=y
-+# CONFIG_X86_MCE_AMD is not set
-+# CONFIG_X86_ANCIENT_MCE is not set
-+CONFIG_X86_MCE_THRESHOLD=y
-+# CONFIG_X86_MCE_INJECT is not set
-+CONFIG_X86_THERMAL_VECTOR=y
-+CONFIG_VM86=y
-+# CONFIG_TOSHIBA is not set
-+# CONFIG_I8K is not set
-+CONFIG_X86_REBOOTFIXUPS=y
-+CONFIG_MICROCODE=y
-+CONFIG_MICROCODE_INTEL=y
-+# CONFIG_MICROCODE_AMD is not set
-+CONFIG_MICROCODE_OLD_INTERFACE=y
-+CONFIG_X86_MSR=y
-+CONFIG_X86_CPUID=y
-+# CONFIG_NOHIGHMEM is not set
-+# CONFIG_HIGHMEM4G is not set
-+CONFIG_HIGHMEM64G=y
-+CONFIG_VMSPLIT_3G=y
-+# CONFIG_VMSPLIT_2G is not set
-+# CONFIG_VMSPLIT_1G is not set
-+CONFIG_PAGE_OFFSET=0xC0000000
-+CONFIG_HIGHMEM=y
-+CONFIG_X86_PAE=y
-+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
-+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
-+CONFIG_ARCH_FLATMEM_ENABLE=y
-+CONFIG_ARCH_SPARSEMEM_ENABLE=y
-+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-+CONFIG_ILLEGAL_POINTER_VALUE=0
-+CONFIG_SELECT_MEMORY_MODEL=y
-+CONFIG_FLATMEM_MANUAL=y
-+# CONFIG_SPARSEMEM_MANUAL is not set
-+CONFIG_FLATMEM=y
-+CONFIG_FLAT_NODE_MEM_MAP=y
-+CONFIG_SPARSEMEM_STATIC=y
-+CONFIG_HAVE_MEMBLOCK=y
-+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
-+CONFIG_ARCH_DISCARD_MEMBLOCK=y
-+CONFIG_PAGEFLAGS_EXTENDED=y
-+CONFIG_SPLIT_PTLOCK_CPUS=999999
-+# CONFIG_COMPACTION is not set
-+CONFIG_PHYS_ADDR_T_64BIT=y
-+CONFIG_ZONE_DMA_FLAG=0
-+CONFIG_BOUNCE=y
-+CONFIG_VIRT_TO_BUS=y
-+# CONFIG_KSM is not set
-+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
-+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
-+# CONFIG_MEMORY_FAILURE is not set
-+# CONFIG_TRANSPARENT_HUGEPAGE is not set
-+CONFIG_CROSS_MEMORY_ATTACH=y
-+CONFIG_NEED_PER_CPU_KM=y
-+# CONFIG_CLEANCACHE is not set
-+# CONFIG_HIGHPTE is not set
-+# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
-+CONFIG_X86_RESERVE_LOW=64
-+# CONFIG_MATH_EMULATION is not set
-+# CONFIG_MTRR is not set
-+# CONFIG_ARCH_RANDOM is not set
-+CONFIG_X86_SMAP=y
-+CONFIG_EFI=y
-+CONFIG_EFI_STUB=y
-+CONFIG_EFI_CAPSULE=y
-+CONFIG_SECCOMP=y
-+# CONFIG_CC_STACKPROTECTOR is not set
-+CONFIG_HZ_100=y
-+# CONFIG_HZ_250 is not set
-+# CONFIG_HZ_300 is not set
-+# CONFIG_HZ_1000 is not set
-+CONFIG_HZ=100
-+CONFIG_SCHED_HRTICK=y
-+CONFIG_KEXEC=y
-+# CONFIG_CRASH_DUMP is not set
-+CONFIG_PHYSICAL_START=0x400000
-+# CONFIG_RELOCATABLE is not set
-+CONFIG_PHYSICAL_ALIGN=0x1000000
-+# CONFIG_COMPAT_VDSO is not set
-+# CONFIG_CMDLINE_BOOL is not set
-+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-+
-+#
-+# Power management and ACPI options
-+#
-+CONFIG_SUSPEND=y
-+CONFIG_SUSPEND_FREEZER=y
-+CONFIG_PM_SLEEP=y
-+# CONFIG_PM_AUTOSLEEP is not set
-+# CONFIG_PM_WAKELOCKS is not set
-+CONFIG_PM_RUNTIME=y
-+CONFIG_PM=y
-+CONFIG_PM_DEBUG=y
-+# CONFIG_PM_ADVANCED_DEBUG is not set
-+CONFIG_PM_SLEEP_DEBUG=y
-+CONFIG_PM_TRACE=y
-+CONFIG_PM_TRACE_RTC=y
-+CONFIG_ACPI=y
-+CONFIG_ACPI_SLEEP=y
-+CONFIG_ACPI_PROCFS=y
-+CONFIG_ACPI_PROCFS_POWER=y
-+CONFIG_ACPI_EC_DEBUGFS=y
-+# CONFIG_ACPI_PROC_EVENT is not set
-+CONFIG_ACPI_AC=y
-+# CONFIG_ACPI_BATTERY is not set
-+CONFIG_ACPI_BUTTON=y
-+# CONFIG_ACPI_FAN is not set
-+# CONFIG_ACPI_DOCK is not set
-+CONFIG_ACPI_I2C=m
-+CONFIG_ACPI_PROCESSOR=y
-+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
-+CONFIG_ACPI_THERMAL=y
-+# CONFIG_ACPI_CUSTOM_DSDT is not set
-+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
-+CONFIG_ACPI_BLACKLIST_YEAR=0
-+CONFIG_ACPI_DEBUG=y
-+# CONFIG_ACPI_DEBUG_FUNC_TRACE is not set
-+CONFIG_ACPI_PCI_SLOT=y
-+CONFIG_X86_PM_TIMER=y
-+# CONFIG_ACPI_CONTAINER is not set
-+# CONFIG_ACPI_SBS is not set
-+# CONFIG_ACPI_HED is not set
-+# CONFIG_ACPI_CUSTOM_METHOD is not set
-+# CONFIG_ACPI_BGRT is not set
-+# CONFIG_ACPI_APEI is not set
-+# CONFIG_SFI is not set
-+# CONFIG_APM is not set
-+
-+#
-+# CPU Frequency scaling
-+#
-+# CONFIG_CPU_FREQ is not set
-+CONFIG_CPU_IDLE=y
-+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
-+CONFIG_CPU_IDLE_GOV_LADDER=y
-+CONFIG_CPU_IDLE_GOV_MENU=y
-+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
-+# CONFIG_INTEL_IDLE is not set
-+
-+#
-+# Bus options (PCI etc.)
-+#
-+CONFIG_PCI=y
-+# CONFIG_PCI_GOBIOS is not set
-+# CONFIG_PCI_GOMMCONFIG is not set
-+# CONFIG_PCI_GODIRECT is not set
-+CONFIG_PCI_GOANY=y
-+CONFIG_PCI_BIOS=y
-+CONFIG_PCI_DIRECT=y
-+CONFIG_PCI_MMCONFIG=y
-+CONFIG_PCI_DOMAINS=y
-+# CONFIG_PCI_CNB20LE_QUIRK is not set
-+CONFIG_PCIEPORTBUS=y
-+CONFIG_PCIEAER=y
-+# CONFIG_PCIE_ECRC is not set
-+# CONFIG_PCIEAER_INJECT is not set
-+CONFIG_PCIEASPM=y
-+# CONFIG_PCIEASPM_DEBUG is not set
-+CONFIG_PCIEASPM_DEFAULT=y
-+# CONFIG_PCIEASPM_POWERSAVE is not set
-+# CONFIG_PCIEASPM_PERFORMANCE is not set
-+CONFIG_PCIE_PME=y
-+CONFIG_ARCH_SUPPORTS_MSI=y
-+CONFIG_PCI_MSI=y
-+CONFIG_PCI_DEBUG=y
-+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
-+# CONFIG_PCI_STUB is not set
-+CONFIG_HT_IRQ=y
-+# CONFIG_PCI_IOV is not set
-+# CONFIG_PCI_PRI is not set
-+# CONFIG_PCI_PASID is not set
-+CONFIG_PCI_IOAPIC=y
-+CONFIG_PCI_LABEL=y
-+CONFIG_ISA_DMA_API=y
-+# CONFIG_ISA is not set
-+# CONFIG_SCx200 is not set
-+# CONFIG_ALIX is not set
-+# CONFIG_NET5501 is not set
-+CONFIG_AMD_NB=y
-+# CONFIG_PCCARD is not set
-+# CONFIG_HOTPLUG_PCI is not set
-+# CONFIG_RAPIDIO is not set
-+
-+#
-+# Executable file formats / Emulations
-+#
-+CONFIG_BINFMT_ELF=y
-+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
-+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
-+CONFIG_HAVE_AOUT=y
-+# CONFIG_BINFMT_AOUT is not set
-+# CONFIG_BINFMT_MISC is not set
-+CONFIG_COREDUMP=y
-+CONFIG_HAVE_ATOMIC_IOMAP=y
-+CONFIG_HAVE_TEXT_POKE_SMP=y
-+CONFIG_NET=y
-+
-+#
-+# Networking options
-+#
-+CONFIG_PACKET=y
-+# CONFIG_PACKET_DIAG is not set
-+CONFIG_UNIX=y
-+# CONFIG_UNIX_DIAG is not set
-+CONFIG_XFRM=y
-+# CONFIG_XFRM_USER is not set
-+# CONFIG_XFRM_SUB_POLICY is not set
-+# CONFIG_XFRM_MIGRATE is not set
-+# CONFIG_XFRM_STATISTICS is not set
-+# CONFIG_NET_KEY is not set
-+CONFIG_INET=y
-+# CONFIG_IP_MULTICAST is not set
-+# CONFIG_IP_ADVANCED_ROUTER is not set
-+# CONFIG_IP_PNP is not set
-+# CONFIG_NET_IPIP is not set
-+# CONFIG_NET_IPGRE_DEMUX is not set
-+# CONFIG_ARPD is not set
-+CONFIG_SYN_COOKIES=y
-+# CONFIG_NET_IPVTI is not set
-+# CONFIG_INET_AH is not set
-+# CONFIG_INET_ESP is not set
-+# CONFIG_INET_IPCOMP is not set
-+# CONFIG_INET_XFRM_TUNNEL is not set
-+# CONFIG_INET_TUNNEL is not set
-+CONFIG_INET_XFRM_MODE_TRANSPORT=y
-+CONFIG_INET_XFRM_MODE_TUNNEL=y
-+CONFIG_INET_XFRM_MODE_BEET=y
-+CONFIG_INET_LRO=y
-+CONFIG_INET_DIAG=y
-+CONFIG_INET_TCP_DIAG=y
-+# CONFIG_INET_UDP_DIAG is not set
-+# CONFIG_TCP_CONG_ADVANCED is not set
-+CONFIG_TCP_CONG_CUBIC=y
-+CONFIG_DEFAULT_TCP_CONG="cubic"
-+# CONFIG_TCP_MD5SIG is not set
-+CONFIG_IPV6=m
-+# CONFIG_IPV6_PRIVACY is not set
-+# CONFIG_IPV6_ROUTER_PREF is not set
-+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-+# CONFIG_INET6_AH is not set
-+# CONFIG_INET6_ESP is not set
-+# CONFIG_INET6_IPCOMP is not set
-+# CONFIG_IPV6_MIP6 is not set
-+# CONFIG_INET6_XFRM_TUNNEL is not set
-+# CONFIG_INET6_TUNNEL is not set
-+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET6_XFRM_MODE_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_BEET=m
-+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-+# CONFIG_IPV6_SIT is not set
-+# CONFIG_IPV6_TUNNEL is not set
-+# CONFIG_IPV6_GRE is not set
-+# CONFIG_IPV6_MULTIPLE_TABLES is not set
-+# CONFIG_IPV6_MROUTE is not set
-+# CONFIG_NETLABEL is not set
-+# CONFIG_NETWORK_SECMARK is not set
-+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
-+# CONFIG_NETFILTER is not set
-+# CONFIG_IP_DCCP is not set
-+# CONFIG_IP_SCTP is not set
-+# CONFIG_RDS is not set
-+# CONFIG_TIPC is not set
-+# CONFIG_ATM is not set
-+# CONFIG_L2TP is not set
-+CONFIG_STP=m
-+CONFIG_GARP=m
-+# CONFIG_BRIDGE is not set
-+CONFIG_HAVE_NET_DSA=y
-+CONFIG_VLAN_8021Q=m
-+CONFIG_VLAN_8021Q_GVRP=y
-+# CONFIG_DECNET is not set
-+CONFIG_LLC=m
-+# CONFIG_LLC2 is not set
-+# CONFIG_IPX is not set
-+# CONFIG_ATALK is not set
-+# CONFIG_X25 is not set
-+# CONFIG_LAPB is not set
-+# CONFIG_WAN_ROUTER is not set
-+# CONFIG_PHONET is not set
-+# CONFIG_IEEE802154 is not set
-+# CONFIG_NET_SCHED is not set
-+# CONFIG_DCB is not set
-+# CONFIG_DNS_RESOLVER is not set
-+# CONFIG_BATMAN_ADV is not set
-+# CONFIG_OPENVSWITCH is not set
-+# CONFIG_NETPRIO_CGROUP is not set
-+CONFIG_BQL=y
-+
-+#
-+# Network testing
-+#
-+# CONFIG_NET_PKTGEN is not set
-+# CONFIG_HAMRADIO is not set
-+# CONFIG_CAN is not set
-+# CONFIG_IRDA is not set
-+CONFIG_BT=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+
-+#
-+# Bluetooth device drivers
-+#
-+CONFIG_BT_HCIBTUSB=m
-+# CONFIG_BT_HCIBTSDIO is not set
-+# CONFIG_BT_HCIUART is not set
-+# CONFIG_BT_HCIBCM203X is not set
-+# CONFIG_BT_HCIBPA10X is not set
-+# CONFIG_BT_HCIBFUSB is not set
-+CONFIG_BT_HCIVHCI=m
-+# CONFIG_BT_MRVL is not set
-+# CONFIG_BT_ATH3K is not set
-+# CONFIG_AF_RXRPC is not set
-+CONFIG_WIRELESS=y
-+CONFIG_WEXT_CORE=y
-+CONFIG_WEXT_PROC=y
-+CONFIG_CFG80211=m
-+# CONFIG_NL80211_TESTMODE is not set
-+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
-+# CONFIG_CFG80211_REG_DEBUG is not set
-+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
-+CONFIG_CFG80211_DEFAULT_PS=y
-+# CONFIG_CFG80211_DEBUGFS is not set
-+# CONFIG_CFG80211_INTERNAL_REGDB is not set
-+CONFIG_CFG80211_WEXT=y
-+# CONFIG_LIB80211 is not set
-+CONFIG_MAC80211=m
-+CONFIG_MAC80211_HAS_RC=y
-+# CONFIG_MAC80211_RC_PID is not set
-+CONFIG_MAC80211_RC_MINSTREL=y
-+CONFIG_MAC80211_RC_MINSTREL_HT=y
-+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
-+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
-+# CONFIG_MAC80211_MESH is not set
-+CONFIG_MAC80211_LEDS=y
-+# CONFIG_MAC80211_DEBUGFS is not set
-+# CONFIG_MAC80211_MESSAGE_TRACING is not set
-+# CONFIG_MAC80211_DEBUG_MENU is not set
-+# CONFIG_WIMAX is not set
-+CONFIG_RFKILL=m
-+CONFIG_RFKILL_LEDS=y
-+CONFIG_RFKILL_INPUT=y
-+# CONFIG_NET_9P is not set
-+# CONFIG_CAIF is not set
-+# CONFIG_CEPH_LIB is not set
-+# CONFIG_NFC is not set
-+
-+#
-+# Device Drivers
-+#
-+
-+#
-+# Generic Driver Options
-+#
-+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-+CONFIG_DEVTMPFS=y
-+CONFIG_DEVTMPFS_MOUNT=y
-+CONFIG_STANDALONE=y
-+CONFIG_PREVENT_FIRMWARE_BUILD=y
-+CONFIG_FW_LOADER=y
-+CONFIG_FIRMWARE_IN_KERNEL=y
-+CONFIG_EXTRA_FIRMWARE=""
-+# CONFIG_DEBUG_DRIVER is not set
-+CONFIG_DEBUG_DEVRES=y
-+# CONFIG_SYS_HYPERVISOR is not set
-+# CONFIG_GENERIC_CPU_DEVICES is not set
-+CONFIG_DMA_SHARED_BUFFER=y
-+# CONFIG_CMA is not set
-+
-+#
-+# Bus devices
-+#
-+# CONFIG_CONNECTOR is not set
-+CONFIG_MTD=y
-+# CONFIG_MTD_TESTS is not set
-+# CONFIG_MTD_REDBOOT_PARTS is not set
-+# CONFIG_MTD_CMDLINE_PARTS is not set
-+# CONFIG_MTD_AR7_PARTS is not set
-+
-+#
-+# User Modules And Translation Layers
-+#
-+CONFIG_MTD_CHAR=m
-+CONFIG_MTD_BLKDEVS=m
-+CONFIG_MTD_BLOCK=m
-+# CONFIG_MTD_BLOCK_RO is not set
-+# CONFIG_FTL is not set
-+# CONFIG_NFTL is not set
-+# CONFIG_INFTL is not set
-+# CONFIG_RFD_FTL is not set
-+# CONFIG_SSFDC is not set
-+# CONFIG_SM_FTL is not set
-+# CONFIG_MTD_OOPS is not set
-+
-+#
-+# RAM/ROM/Flash chip drivers
-+#
-+# CONFIG_MTD_CFI is not set
-+# CONFIG_MTD_JEDECPROBE is not set
-+CONFIG_MTD_MAP_BANK_WIDTH_1=y
-+CONFIG_MTD_MAP_BANK_WIDTH_2=y
-+CONFIG_MTD_MAP_BANK_WIDTH_4=y
-+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-+CONFIG_MTD_CFI_I1=y
-+CONFIG_MTD_CFI_I2=y
-+# CONFIG_MTD_CFI_I4 is not set
-+# CONFIG_MTD_CFI_I8 is not set
-+# CONFIG_MTD_RAM is not set
-+# CONFIG_MTD_ROM is not set
-+# CONFIG_MTD_ABSENT is not set
-+
-+#
-+# Mapping drivers for chip access
-+#
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-+# CONFIG_MTD_TS5500 is not set
-+# CONFIG_MTD_INTEL_VR_NOR is not set
-+# CONFIG_MTD_PLATRAM is not set
-+
-+#
-+# Self-contained MTD device drivers
-+#
-+# CONFIG_MTD_PMC551 is not set
-+# CONFIG_MTD_DATAFLASH is not set
-+CONFIG_MTD_M25P80=m
-+CONFIG_M25PXX_USE_FAST_READ=y
-+# CONFIG_MTD_SST25L is not set
-+# CONFIG_MTD_SLRAM is not set
-+# CONFIG_MTD_PHRAM is not set
-+# CONFIG_MTD_MTDRAM is not set
-+# CONFIG_MTD_MTD_CLN_ROM is not set
-+# CONFIG_MTD_BLOCK2MTD is not set
-+
-+#
-+# Disk-On-Chip Device Drivers
-+#
-+# CONFIG_MTD_DOCG3 is not set
-+# CONFIG_MTD_NAND is not set
-+# CONFIG_MTD_ONENAND is not set
-+
-+#
-+# LPDDR flash memory drivers
-+#
-+# CONFIG_MTD_LPDDR is not set
-+# CONFIG_MTD_UBI is not set
-+# CONFIG_PARPORT is not set
-+CONFIG_PNP=y
-+# CONFIG_PNP_DEBUG_MESSAGES is not set
-+
-+#
-+# Protocols
-+#
-+CONFIG_PNPACPI=y
-+CONFIG_BLK_DEV=y
-+# CONFIG_BLK_DEV_FD is not set
-+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
-+# CONFIG_BLK_CPQ_DA is not set
-+# CONFIG_BLK_CPQ_CISS_DA is not set
-+# CONFIG_BLK_DEV_DAC960 is not set
-+# CONFIG_BLK_DEV_UMEM is not set
-+# CONFIG_BLK_DEV_COW_COMMON is not set
-+CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
-+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-+# CONFIG_BLK_DEV_DRBD is not set
-+# CONFIG_BLK_DEV_NBD is not set
-+# CONFIG_BLK_DEV_NVME is not set
-+# CONFIG_BLK_DEV_SX8 is not set
-+CONFIG_BLK_DEV_RAM=y
-+CONFIG_BLK_DEV_RAM_COUNT=1
-+CONFIG_BLK_DEV_RAM_SIZE=81920
-+# CONFIG_BLK_DEV_XIP is not set
-+# CONFIG_CDROM_PKTCDVD is not set
-+# CONFIG_ATA_OVER_ETH is not set
-+# CONFIG_BLK_DEV_HD is not set
-+# CONFIG_BLK_DEV_RBD is not set
-+
-+#
-+# Misc devices
-+#
-+# CONFIG_SENSORS_LIS3LV02D is not set
-+# CONFIG_AD525X_DPOT is not set
-+# CONFIG_IBM_ASM is not set
-+# CONFIG_PHANTOM is not set
-+# CONFIG_INTEL_MID_PTI is not set
-+# CONFIG_SGI_IOC4 is not set
-+# CONFIG_TIFM_CORE is not set
-+# CONFIG_ICS932S401 is not set
-+# CONFIG_ENCLOSURE_SERVICES is not set
-+# CONFIG_HP_ILO is not set
-+# CONFIG_APDS9802ALS is not set
-+# CONFIG_ISL29003 is not set
-+# CONFIG_ISL29020 is not set
-+# CONFIG_SENSORS_TSL2550 is not set
-+# CONFIG_SENSORS_BH1780 is not set
-+# CONFIG_SENSORS_BH1770 is not set
-+# CONFIG_SENSORS_APDS990X is not set
-+# CONFIG_HMC6352 is not set
-+# CONFIG_DS1682 is not set
-+# CONFIG_TI_DAC7512 is not set
-+# CONFIG_VMWARE_BALLOON is not set
-+# CONFIG_BMP085_I2C is not set
-+# CONFIG_BMP085_SPI is not set
-+# CONFIG_PCH_PHUB is not set
-+# CONFIG_USB_SWITCH_FSA9480 is not set
-+# CONFIG_C2PORT is not set
-+
-+#
-+# EEPROM support
-+#
-+CONFIG_EEPROM_AT24=m
-+# CONFIG_EEPROM_AT25 is not set
-+# CONFIG_EEPROM_LEGACY is not set
-+# CONFIG_EEPROM_MAX6875 is not set
-+# CONFIG_EEPROM_93CX6 is not set
-+# CONFIG_EEPROM_93XX46 is not set
-+# CONFIG_CB710_CORE is not set
-+
-+#
-+# Texas Instruments shared transport line discipline
-+#
-+# CONFIG_TI_ST is not set
-+# CONFIG_SENSORS_LIS3_I2C is not set
-+
-+#
-+# Altera FPGA firmware download module
-+#
-+# CONFIG_ALTERA_STAPL is not set
-+CONFIG_HAVE_IDE=y
-+# CONFIG_IDE is not set
-+
-+#
-+# SCSI device support
-+#
-+CONFIG_SCSI_MOD=y
-+# CONFIG_RAID_ATTRS is not set
-+CONFIG_SCSI=y
-+CONFIG_SCSI_DMA=y
-+# CONFIG_SCSI_TGT is not set
-+# CONFIG_SCSI_NETLINK is not set
-+CONFIG_SCSI_PROC_FS=y
-+
-+#
-+# SCSI support type (disk, tape, CD-ROM)
-+#
-+CONFIG_BLK_DEV_SD=y
-+# CONFIG_CHR_DEV_ST is not set
-+# CONFIG_CHR_DEV_OSST is not set
-+# CONFIG_BLK_DEV_SR is not set
-+CONFIG_CHR_DEV_SG=y
-+# CONFIG_CHR_DEV_SCH is not set
-+# CONFIG_SCSI_MULTI_LUN is not set
-+CONFIG_SCSI_CONSTANTS=y
-+# CONFIG_SCSI_LOGGING is not set
-+# CONFIG_SCSI_SCAN_ASYNC is not set
-+
-+#
-+# SCSI Transports
-+#
-+CONFIG_SCSI_SPI_ATTRS=y
-+# CONFIG_SCSI_FC_ATTRS is not set
-+# CONFIG_SCSI_ISCSI_ATTRS is not set
-+# CONFIG_SCSI_SAS_ATTRS is not set
-+# CONFIG_SCSI_SAS_LIBSAS is not set
-+# CONFIG_SCSI_SRP_ATTRS is not set
-+# CONFIG_SCSI_LOWLEVEL is not set
-+# CONFIG_SCSI_DH is not set
-+# CONFIG_SCSI_OSD_INITIATOR is not set
-+# CONFIG_ATA is not set
-+# CONFIG_MD is not set
-+# CONFIG_TARGET_CORE is not set
-+# CONFIG_FUSION is not set
-+
-+#
-+# IEEE 1394 (FireWire) support
-+#
-+# CONFIG_FIREWIRE is not set
-+# CONFIG_FIREWIRE_NOSY is not set
-+# CONFIG_I2O is not set
-+# CONFIG_MACINTOSH_DRIVERS is not set
-+CONFIG_NETDEVICES=y
-+CONFIG_NET_CORE=y
-+# CONFIG_BONDING is not set
-+# CONFIG_DUMMY is not set
-+# CONFIG_EQUALIZER is not set
-+# CONFIG_NET_FC is not set
-+CONFIG_MII=y
-+# CONFIG_NET_TEAM is not set
-+# CONFIG_MACVLAN is not set
-+# CONFIG_VXLAN is not set
-+# CONFIG_NETCONSOLE is not set
-+# CONFIG_NETPOLL is not set
-+# CONFIG_NET_POLL_CONTROLLER is not set
-+# CONFIG_TUN is not set
-+# CONFIG_VETH is not set
-+# CONFIG_ARCNET is not set
-+
-+#
-+# CAIF transport drivers
-+#
-+
-+#
-+# Distributed Switch Architecture drivers
-+#
-+# CONFIG_NET_DSA_MV88E6XXX is not set
-+# CONFIG_NET_DSA_MV88E6060 is not set
-+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
-+# CONFIG_NET_DSA_MV88E6131 is not set
-+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
-+CONFIG_ETHERNET=y
-+# CONFIG_NET_VENDOR_3COM is not set
-+# CONFIG_NET_VENDOR_ADAPTEC is not set
-+# CONFIG_NET_VENDOR_ALTEON is not set
-+# CONFIG_NET_VENDOR_AMD is not set
-+# CONFIG_NET_VENDOR_ATHEROS is not set
-+CONFIG_NET_CADENCE=y
-+# CONFIG_ARM_AT91_ETHER is not set
-+# CONFIG_MACB is not set
-+# CONFIG_NET_VENDOR_BROADCOM is not set
-+# CONFIG_NET_VENDOR_BROCADE is not set
-+# CONFIG_NET_CALXEDA_XGMAC is not set
-+# CONFIG_NET_VENDOR_CHELSIO is not set
-+# CONFIG_NET_VENDOR_CISCO is not set
-+# CONFIG_DNET is not set
-+# CONFIG_NET_VENDOR_DEC is not set
-+# CONFIG_NET_VENDOR_DLINK is not set
-+# CONFIG_NET_VENDOR_EMULEX is not set
-+# CONFIG_NET_VENDOR_EXAR is not set
-+# CONFIG_NET_VENDOR_HP is not set
-+CONFIG_NET_VENDOR_INTEL=y
-+# CONFIG_E100 is not set
-+CONFIG_E1000=m
-+# CONFIG_E1000E is not set
-+# CONFIG_IGB is not set
-+# CONFIG_IGBVF is not set
-+# CONFIG_IXGB is not set
-+# CONFIG_IXGBE is not set
-+# CONFIG_IXGBEVF is not set
-+# CONFIG_NET_VENDOR_I825XX is not set
-+# CONFIG_IP1000 is not set
-+# CONFIG_JME is not set
-+# CONFIG_NET_VENDOR_MARVELL is not set
-+# CONFIG_NET_VENDOR_MELLANOX is not set
-+# CONFIG_NET_VENDOR_MICREL is not set
-+# CONFIG_NET_VENDOR_MICROCHIP is not set
-+# CONFIG_NET_VENDOR_MYRI is not set
-+# CONFIG_FEALNX is not set
-+# CONFIG_NET_VENDOR_NATSEMI is not set
-+# CONFIG_NET_VENDOR_NVIDIA is not set
-+# CONFIG_NET_VENDOR_OKI is not set
-+# CONFIG_ETHOC is not set
-+# CONFIG_NET_PACKET_ENGINE is not set
-+# CONFIG_NET_VENDOR_QLOGIC is not set
-+# CONFIG_NET_VENDOR_REALTEK is not set
-+# CONFIG_NET_VENDOR_RDC is not set
-+# CONFIG_NET_VENDOR_SEEQ is not set
-+# CONFIG_NET_VENDOR_SILAN is not set
-+# CONFIG_NET_VENDOR_SIS is not set
-+# CONFIG_SFC is not set
-+# CONFIG_NET_VENDOR_SMSC is not set
-+CONFIG_NET_VENDOR_STMICRO=y
-+CONFIG_STMMAC_ETH=m
-+# CONFIG_STMMAC_PLATFORM is not set
-+CONFIG_STMMAC_PCI=y
-+# CONFIG_STMMAC_DEBUG_FS is not set
-+CONFIG_STMMAC_DA=y
-+# CONFIG_STMMAC_PTP is not set
-+CONFIG_STMMAC_RING=y
-+# CONFIG_STMMAC_CHAINED is not set
-+# CONFIG_NET_VENDOR_SUN is not set
-+# CONFIG_NET_VENDOR_TEHUTI is not set
-+# CONFIG_NET_VENDOR_TI is not set
-+# CONFIG_NET_VENDOR_VIA is not set
-+# CONFIG_NET_VENDOR_WIZNET is not set
-+# CONFIG_FDDI is not set
-+# CONFIG_HIPPI is not set
-+# CONFIG_NET_SB1000 is not set
-+CONFIG_PHYLIB=y
-+
-+#
-+# MII PHY device drivers
-+#
-+# CONFIG_AT803X_PHY is not set
-+# CONFIG_AMD_PHY is not set
-+# CONFIG_MARVELL_PHY is not set
-+# CONFIG_DAVICOM_PHY is not set
-+# CONFIG_QSEMI_PHY is not set
-+# CONFIG_LXT_PHY is not set
-+# CONFIG_CICADA_PHY is not set
-+# CONFIG_VITESSE_PHY is not set
-+# CONFIG_SMSC_PHY is not set
-+# CONFIG_BROADCOM_PHY is not set
-+# CONFIG_BCM87XX_PHY is not set
-+# CONFIG_ICPLUS_PHY is not set
-+# CONFIG_REALTEK_PHY is not set
-+# CONFIG_NATIONAL_PHY is not set
-+# CONFIG_STE10XP is not set
-+# CONFIG_LSI_ET1011C_PHY is not set
-+# CONFIG_MICREL_PHY is not set
-+# CONFIG_FIXED_PHY is not set
-+# CONFIG_MDIO_BITBANG is not set
-+# CONFIG_MICREL_KS8995MA is not set
-+CONFIG_PPP=m
-+# CONFIG_PPP_BSDCOMP is not set
-+CONFIG_PPP_DEFLATE=m
-+# CONFIG_PPP_FILTER is not set
-+# CONFIG_PPP_MPPE is not set
-+# CONFIG_PPP_MULTILINK is not set
-+# CONFIG_PPPOE is not set
-+CONFIG_PPP_ASYNC=m
-+# CONFIG_PPP_SYNC_TTY is not set
-+# CONFIG_SLIP is not set
-+CONFIG_SLHC=m
-+
-+#
-+# USB Network Adapters
-+#
-+# CONFIG_USB_CATC is not set
-+# CONFIG_USB_KAWETH is not set
-+# CONFIG_USB_PEGASUS is not set
-+# CONFIG_USB_RTL8150 is not set
-+# CONFIG_USB_USBNET is not set
-+# CONFIG_USB_HSO is not set
-+# CONFIG_USB_IPHETH is not set
-+CONFIG_WLAN=y
-+# CONFIG_LIBERTAS_THINFIRM is not set
-+# CONFIG_AIRO is not set
-+# CONFIG_ATMEL is not set
-+# CONFIG_AT76C50X_USB is not set
-+# CONFIG_PRISM54 is not set
-+# CONFIG_USB_ZD1201 is not set
-+# CONFIG_USB_NET_RNDIS_WLAN is not set
-+# CONFIG_RTL8180 is not set
-+# CONFIG_RTL8187 is not set
-+# CONFIG_ADM8211 is not set
-+# CONFIG_MAC80211_HWSIM is not set
-+# CONFIG_MWL8K is not set
-+# CONFIG_ATH_CARDS is not set
-+# CONFIG_B43 is not set
-+# CONFIG_B43LEGACY is not set
-+# CONFIG_BRCMFMAC is not set
-+# CONFIG_HOSTAP is not set
-+# CONFIG_IPW2100 is not set
-+# CONFIG_IPW2200 is not set
-+CONFIG_IWLWIFI=m
-+CONFIG_IWLDVM=m
-+
-+#
-+# Debugging Options
-+#
-+# CONFIG_IWLWIFI_DEBUG is not set
-+CONFIG_IWLWIFI_P2P=y
-+# CONFIG_IWL4965 is not set
-+# CONFIG_IWL3945 is not set
-+# CONFIG_LIBERTAS is not set
-+# CONFIG_HERMES is not set
-+# CONFIG_P54_COMMON is not set
-+# CONFIG_RT2X00 is not set
-+# CONFIG_RTL8192CE is not set
-+# CONFIG_RTL8192SE is not set
-+# CONFIG_RTL8192DE is not set
-+# CONFIG_RTL8723AE is not set
-+# CONFIG_RTL8192CU is not set
-+# CONFIG_WL_TI is not set
-+# CONFIG_ZD1211RW is not set
-+# CONFIG_MWIFIEX is not set
-+
-+#
-+# Enable WiMAX (Networking options) to see the WiMAX drivers
-+#
-+# CONFIG_WAN is not set
-+# CONFIG_VMXNET3 is not set
-+# CONFIG_ISDN is not set
-+
-+#
-+# Input device support
-+#
-+CONFIG_INPUT=y
-+# CONFIG_INPUT_FF_MEMLESS is not set
-+# CONFIG_INPUT_POLLDEV is not set
-+# CONFIG_INPUT_SPARSEKMAP is not set
-+# CONFIG_INPUT_MATRIXKMAP is not set
-+
-+#
-+# Userland interfaces
-+#
-+# CONFIG_INPUT_MOUSEDEV is not set
-+# CONFIG_INPUT_JOYDEV is not set
-+CONFIG_INPUT_EVDEV=m
-+# CONFIG_INPUT_EVBUG is not set
-+
-+#
-+# Input Device Drivers
-+#
-+# CONFIG_INPUT_KEYBOARD is not set
-+# CONFIG_INPUT_MOUSE is not set
-+# CONFIG_INPUT_JOYSTICK is not set
-+# CONFIG_INPUT_TABLET is not set
-+# CONFIG_INPUT_TOUCHSCREEN is not set
-+# CONFIG_INPUT_MISC is not set
-+
-+#
-+# Hardware I/O ports
-+#
-+# CONFIG_SERIO is not set
-+# CONFIG_GAMEPORT is not set
-+
-+#
-+# Character devices
-+#
-+CONFIG_VT=y
-+CONFIG_CONSOLE_TRANSLATIONS=y
-+CONFIG_VT_CONSOLE=y
-+CONFIG_VT_CONSOLE_SLEEP=y
-+CONFIG_HW_CONSOLE=y
-+CONFIG_VT_HW_CONSOLE_BINDING=y
-+CONFIG_UNIX98_PTYS=y
-+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
-+CONFIG_LEGACY_PTYS=y
-+CONFIG_LEGACY_PTY_COUNT=32
-+CONFIG_SERIAL_NONSTANDARD=y
-+# CONFIG_ROCKETPORT is not set
-+# CONFIG_CYCLADES is not set
-+# CONFIG_MOXA_INTELLIO is not set
-+# CONFIG_MOXA_SMARTIO is not set
-+# CONFIG_SYNCLINK is not set
-+# CONFIG_SYNCLINKMP is not set
-+# CONFIG_SYNCLINK_GT is not set
-+# CONFIG_NOZOMI is not set
-+# CONFIG_ISI is not set
-+# CONFIG_N_HDLC is not set
-+# CONFIG_N_GSM is not set
-+# CONFIG_TRACE_SINK is not set
-+CONFIG_DEVKMEM=y
-+# CONFIG_STALDRV is not set
-+
-+#
-+# Serial drivers
-+#
-+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_NR_UARTS=8
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-+CONFIG_SERIAL_8250_EXTENDED=y
-+CONFIG_SERIAL_8250_MANY_PORTS=y
-+CONFIG_SERIAL_8250_SHARE_IRQ=y
-+CONFIG_SERIAL_8250_DETECT_IRQ=y
-+CONFIG_SERIAL_8250_RSA=y
-+
-+#
-+# Non-8250 serial port support
-+#
-+# CONFIG_SERIAL_MAX3100 is not set
-+# CONFIG_SERIAL_MAX310X is not set
-+# CONFIG_SERIAL_MFD_HSU is not set
-+CONFIG_SERIAL_CORE=y
-+CONFIG_SERIAL_CORE_CONSOLE=y
-+# CONFIG_SERIAL_JSM is not set
-+# CONFIG_SERIAL_SCCNXP is not set
-+# CONFIG_SERIAL_TIMBERDALE is not set
-+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
-+# CONFIG_SERIAL_ALTERA_UART is not set
-+# CONFIG_SERIAL_IFX6X60 is not set
-+# CONFIG_SERIAL_CLN_UART is not set
-+# CONFIG_SERIAL_PCH_UART is not set
-+# CONFIG_SERIAL_ARC is not set
-+# CONFIG_TTY_PRINTK is not set
-+# CONFIG_IPMI_HANDLER is not set
-+# CONFIG_HW_RANDOM is not set
-+# CONFIG_NVRAM is not set
-+CONFIG_RTC=y
-+# CONFIG_R3964 is not set
-+# CONFIG_APPLICOM is not set
-+# CONFIG_SONYPI is not set
-+# CONFIG_MWAVE is not set
-+# CONFIG_PC8736x_GPIO is not set
-+# CONFIG_NSC_GPIO is not set
-+# CONFIG_RAW_DRIVER is not set
-+CONFIG_HPET=y
-+# CONFIG_HPET_MMAP is not set
-+# CONFIG_HANGCHECK_TIMER is not set
-+# CONFIG_TCG_TPM is not set
-+# CONFIG_TELCLOCK is not set
-+CONFIG_DEVPORT=y
-+CONFIG_I2C=m
-+CONFIG_I2C_BOARDINFO=y
-+CONFIG_I2C_COMPAT=y
-+CONFIG_I2C_CHARDEV=m
-+# CONFIG_I2C_MUX is not set
-+CONFIG_I2C_HELPER_AUTO=y
-+
-+#
-+# I2C Hardware Bus support
-+#
-+
-+#
-+# PC SMBus host controller drivers
-+#
-+# CONFIG_I2C_ALI1535 is not set
-+# CONFIG_I2C_ALI1563 is not set
-+# CONFIG_I2C_ALI15X3 is not set
-+# CONFIG_I2C_AMD756 is not set
-+# CONFIG_I2C_AMD8111 is not set
-+# CONFIG_I2C_I801 is not set
-+# CONFIG_I2C_ISCH is not set
-+# CONFIG_I2C_PIIX4 is not set
-+# CONFIG_I2C_NFORCE2 is not set
-+# CONFIG_I2C_SIS5595 is not set
-+# CONFIG_I2C_SIS630 is not set
-+# CONFIG_I2C_SIS96X is not set
-+# CONFIG_I2C_VIA is not set
-+# CONFIG_I2C_VIAPRO is not set
-+
-+#
-+# ACPI drivers
-+#
-+# CONFIG_I2C_SCMI is not set
-+
-+#
-+# I2C system bus drivers (mostly embedded / system-on-chip)
-+#
-+# CONFIG_I2C_CBUS_GPIO is not set
-+# CONFIG_I2C_EG20T is not set
-+# CONFIG_I2C_GPIO is not set
-+# CONFIG_I2C_INTEL_MID is not set
-+# CONFIG_I2C_OCORES is not set
-+# CONFIG_I2C_PCA_PLATFORM is not set
-+# CONFIG_I2C_PXA_PCI is not set
-+# CONFIG_I2C_SIMTEC is not set
-+# CONFIG_I2C_XILINX is not set
-+
-+#
-+# External I2C/SMBus adapter drivers
-+#
-+# CONFIG_I2C_DIOLAN_U2C is not set
-+# CONFIG_I2C_PARPORT_LIGHT is not set
-+# CONFIG_I2C_TINY_USB is not set
-+
-+#
-+# Other I2C/SMBus bus drivers
-+#
-+# CONFIG_SCx200_ACB is not set
-+# CONFIG_I2C_STUB is not set
-+# CONFIG_I2C_DEBUG_CORE is not set
-+# CONFIG_I2C_DEBUG_ALGO is not set
-+# CONFIG_I2C_DEBUG_BUS is not set
-+CONFIG_SPI=y
-+CONFIG_SPI_DEBUG=y
-+CONFIG_GEN3_SPI=y
-+CONFIG_SPI_MASTER=y
-+
-+#
-+# SPI Master Controller Drivers
-+#
-+# CONFIG_SPI_ALTERA is not set
-+CONFIG_SPI_BITBANG=y
-+CONFIG_SPI_GPIO=y
-+# CONFIG_SPI_OC_TINY is not set
-+CONFIG_SPI_PXA2XX=m
-+CONFIG_SPI_PXA2XX_PCI=m
-+# CONFIG_SPI_CE5XX_SPI_SLAVE is not set
-+# CONFIG_SPI_SC18IS602 is not set
-+# CONFIG_SPI_TOPCLIFF_PCH is not set
-+# CONFIG_SPI_XCOMM is not set
-+# CONFIG_SPI_XILINX is not set
-+# CONFIG_SPI_DESIGNWARE is not set
-+# CONFIG_SPI_LPC_SCH is not set
-+
-+#
-+# SPI Protocol Masters
-+#
-+CONFIG_SPI_SPIDEV=m
-+# CONFIG_SPI_TLE62X0 is not set
-+# CONFIG_HSI is not set
-+
-+#
-+# PPS support
-+#
-+CONFIG_PPS=m
-+# CONFIG_PPS_DEBUG is not set
-+
-+#
-+# PPS clients support
-+#
-+# CONFIG_PPS_CLIENT_KTIMER is not set
-+# CONFIG_PPS_CLIENT_LDISC is not set
-+# CONFIG_PPS_CLIENT_GPIO is not set
-+
-+#
-+# PPS generators support
-+#
-+
-+#
-+# PTP clock support
-+#
-+CONFIG_PTP_1588_CLOCK=m
-+
-+#
-+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
-+#
-+CONFIG_PTP_1588_CLOCK_PCH=m
-+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
-+CONFIG_ARCH_REQUIRE_GPIOLIB=y
-+CONFIG_GPIOLIB=y
-+CONFIG_GPIO_ACPI=y
-+# CONFIG_DEBUG_GPIO is not set
-+CONFIG_GPIO_SYSFS=y
-+
-+#
-+# Memory mapped GPIO drivers:
-+#
-+# CONFIG_GPIO_GENERIC_PLATFORM is not set
-+# CONFIG_GPIO_IT8761E is not set
-+# CONFIG_GPIO_TS5500 is not set
-+CONFIG_GPIO_SCH=m
-+# CONFIG_GPIO_ICH is not set
-+# CONFIG_GPIO_VX855 is not set
-+
-+#
-+# I2C GPIO expanders:
-+#
-+# CONFIG_GPIO_MAX7300 is not set
-+# CONFIG_GPIO_MAX732X is not set
-+# CONFIG_GPIO_PCA953X is not set
-+# CONFIG_GPIO_PCF857X is not set
-+# CONFIG_GPIO_ADP5588 is not set
-+
-+#
-+# PCI GPIO expanders:
-+#
-+# CONFIG_GPIO_BT8XX is not set
-+# CONFIG_GPIO_AMD8111 is not set
-+# CONFIG_GPIO_LANGWELL is not set
-+# CONFIG_GPIO_PCH is not set
-+# CONFIG_GPIO_ML_IOH is not set
-+# CONFIG_GPIO_RDC321X is not set
-+
-+#
-+# SPI GPIO expanders:
-+#
-+# CONFIG_GPIO_MAX7301 is not set
-+# CONFIG_GPIO_MCP23S08 is not set
-+# CONFIG_GPIO_MC33880 is not set
-+# CONFIG_GPIO_74X164 is not set
-+
-+#
-+# AC97 GPIO expanders:
-+#
-+
-+#
-+# MODULbus GPIO expanders:
-+#
-+
-+#
-+# USB GPIO expanders:
-+#
-+# CONFIG_W1 is not set
-+CONFIG_POWER_SUPPLY=y
-+# CONFIG_POWER_SUPPLY_DEBUG is not set
-+# CONFIG_PDA_POWER is not set
-+# CONFIG_GENERIC_ADC_BATTERY is not set
-+# CONFIG_TEST_POWER is not set
-+# CONFIG_BATTERY_DS2780 is not set
-+# CONFIG_BATTERY_DS2781 is not set
-+# CONFIG_BATTERY_DS2782 is not set
-+# CONFIG_BATTERY_SBS is not set
-+# CONFIG_BATTERY_BQ27x00 is not set
-+# CONFIG_BATTERY_MAX17040 is not set
-+# CONFIG_BATTERY_MAX17042 is not set
-+# CONFIG_CHARGER_MAX8903 is not set
-+# CONFIG_CHARGER_LP8727 is not set
-+# CONFIG_CHARGER_GPIO is not set
-+# CONFIG_CHARGER_BQ2415X is not set
-+# CONFIG_CHARGER_SMB347 is not set
-+# CONFIG_POWER_RESET is not set
-+# CONFIG_POWER_AVS is not set
-+# CONFIG_HWMON is not set
-+CONFIG_THERMAL=y
-+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
-+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
-+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
-+# CONFIG_FAIR_SHARE is not set
-+CONFIG_STEP_WISE=y
-+# CONFIG_USER_SPACE is not set
-+# CONFIG_WATCHDOG is not set
-+CONFIG_SSB_POSSIBLE=y
-+
-+#
-+# Sonics Silicon Backplane
-+#
-+# CONFIG_SSB is not set
-+CONFIG_BCMA_POSSIBLE=y
-+
-+#
-+# Broadcom specific AMBA
-+#
-+# CONFIG_BCMA is not set
-+
-+#
-+# Multifunction device drivers
-+#
-+CONFIG_MFD_CORE=y
-+# CONFIG_MFD_SM501 is not set
-+# CONFIG_MFD_RTSX_PCI is not set
-+# CONFIG_MFD_TI_AM335X_TSCADC is not set
-+# CONFIG_HTC_PASIC3 is not set
-+# CONFIG_MFD_LM3533 is not set
-+# CONFIG_TPS6105X is not set
-+# CONFIG_TPS65010 is not set
-+# CONFIG_TPS6507X is not set
-+# CONFIG_MFD_TPS65217 is not set
-+# CONFIG_MFD_TPS65912_SPI is not set
-+# CONFIG_MFD_STMPE is not set
-+# CONFIG_MFD_TMIO is not set
-+# CONFIG_MFD_DA9052_SPI is not set
-+# CONFIG_MFD_ARIZONA_I2C is not set
-+# CONFIG_MFD_ARIZONA_SPI is not set
-+# CONFIG_MFD_WM831X_SPI is not set
-+# CONFIG_MFD_PCF50633 is not set
-+# CONFIG_MFD_MC13XXX_SPI is not set
-+# CONFIG_MFD_MC13XXX_I2C is not set
-+# CONFIG_ABX500_CORE is not set
-+# CONFIG_EZX_PCAP is not set
-+# CONFIG_MFD_CS5535 is not set
-+# CONFIG_MFD_TIMBERDALE is not set
-+CONFIG_CY8C9540A=m
-+CONFIG_INTEL_CLN_GIP=m
-+CONFIG_LPC_SCH=y
-+# CONFIG_LPC_ICH is not set
-+# CONFIG_MFD_RDC321X is not set
-+# CONFIG_MFD_JANZ_CMODIO is not set
-+# CONFIG_MFD_VX855 is not set
-+# CONFIG_MFD_WL1273_CORE is not set
-+# CONFIG_MFD_VIPERBOARD is not set
-+# CONFIG_MFD_RETU is not set
-+# CONFIG_REGULATOR is not set
-+CONFIG_MEDIA_SUPPORT=m
-+
-+#
-+# Multimedia core support
-+#
-+CONFIG_MEDIA_CAMERA_SUPPORT=y
-+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
-+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
-+# CONFIG_MEDIA_RADIO_SUPPORT is not set
-+# CONFIG_MEDIA_RC_SUPPORT is not set
-+# CONFIG_MEDIA_CONTROLLER is not set
-+CONFIG_VIDEO_DEV=m
-+CONFIG_VIDEO_V4L2=m
-+# CONFIG_VIDEO_ADV_DEBUG is not set
-+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
-+CONFIG_VIDEOBUF2_CORE=m
-+CONFIG_VIDEOBUF2_MEMOPS=m
-+CONFIG_VIDEOBUF2_VMALLOC=m
-+
-+#
-+# Media drivers
-+#
-+CONFIG_MEDIA_USB_SUPPORT=y
-+
-+#
-+# Webcam devices
-+#
-+CONFIG_USB_VIDEO_CLASS=m
-+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
-+# CONFIG_USB_GSPCA is not set
-+# CONFIG_USB_PWC is not set
-+# CONFIG_VIDEO_CPIA2 is not set
-+# CONFIG_USB_ZR364XX is not set
-+# CONFIG_USB_STKWEBCAM is not set
-+# CONFIG_USB_S2255 is not set
-+# CONFIG_USB_SN9C102 is not set
-+
-+#
-+# Webcam, TV (analog/digital) USB devices
-+#
-+# CONFIG_VIDEO_EM28XX is not set
-+# CONFIG_MEDIA_PCI_SUPPORT is not set
-+# CONFIG_V4L_PLATFORM_DRIVERS is not set
-+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
-+# CONFIG_V4L_TEST_DRIVERS is not set
-+
-+#
-+# Supported MMC/SDIO adapters
-+#
-+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-+
-+#
-+# Media ancillary drivers (tuners, sensors, i2c, frontends)
-+#
-+
-+#
-+# Encoders, decoders, sensors and other helper chips
-+#
-+
-+#
-+# Audio decoders, processors and mixers
-+#
-+# CONFIG_VIDEO_TVAUDIO is not set
-+# CONFIG_VIDEO_TDA7432 is not set
-+# CONFIG_VIDEO_TDA9840 is not set
-+# CONFIG_VIDEO_TEA6415C is not set
-+# CONFIG_VIDEO_TEA6420 is not set
-+# CONFIG_VIDEO_MSP3400 is not set
-+# CONFIG_VIDEO_CS5345 is not set
-+# CONFIG_VIDEO_CS53L32A is not set
-+# CONFIG_VIDEO_TLV320AIC23B is not set
-+# CONFIG_VIDEO_WM8775 is not set
-+# CONFIG_VIDEO_WM8739 is not set
-+# CONFIG_VIDEO_VP27SMPX is not set
-+
-+#
-+# RDS decoders
-+#
-+# CONFIG_VIDEO_SAA6588 is not set
-+
-+#
-+# Video decoders
-+#
-+# CONFIG_VIDEO_ADV7180 is not set
-+# CONFIG_VIDEO_ADV7183 is not set
-+# CONFIG_VIDEO_BT819 is not set
-+# CONFIG_VIDEO_BT856 is not set
-+# CONFIG_VIDEO_BT866 is not set
-+# CONFIG_VIDEO_KS0127 is not set
-+# CONFIG_VIDEO_SAA7110 is not set
-+# CONFIG_VIDEO_SAA711X is not set
-+# CONFIG_VIDEO_SAA7191 is not set
-+# CONFIG_VIDEO_TVP514X is not set
-+# CONFIG_VIDEO_TVP5150 is not set
-+# CONFIG_VIDEO_TVP7002 is not set
-+# CONFIG_VIDEO_VPX3220 is not set
-+
-+#
-+# Video and audio decoders
-+#
-+# CONFIG_VIDEO_SAA717X is not set
-+# CONFIG_VIDEO_CX25840 is not set
-+
-+#
-+# MPEG video encoders
-+#
-+# CONFIG_VIDEO_CX2341X is not set
-+
-+#
-+# Video encoders
-+#
-+# CONFIG_VIDEO_SAA7127 is not set
-+# CONFIG_VIDEO_SAA7185 is not set
-+# CONFIG_VIDEO_ADV7170 is not set
-+# CONFIG_VIDEO_ADV7175 is not set
-+# CONFIG_VIDEO_ADV7343 is not set
-+# CONFIG_VIDEO_ADV7393 is not set
-+# CONFIG_VIDEO_AK881X is not set
-+
-+#
-+# Camera sensor devices
-+#
-+# CONFIG_VIDEO_OV7670 is not set
-+# CONFIG_VIDEO_VS6624 is not set
-+# CONFIG_VIDEO_MT9V011 is not set
-+# CONFIG_VIDEO_TCM825X is not set
-+# CONFIG_VIDEO_SR030PC30 is not set
-+
-+#
-+# Flash devices
-+#
-+
-+#
-+# Video improvement chips
-+#
-+# CONFIG_VIDEO_UPD64031A is not set
-+# CONFIG_VIDEO_UPD64083 is not set
-+
-+#
-+# Miscelaneous helper chips
-+#
-+# CONFIG_VIDEO_THS7303 is not set
-+# CONFIG_VIDEO_M52790 is not set
-+
-+#
-+# Sensors used on soc_camera driver
-+#
-+
-+#
-+# Customise DVB Frontends
-+#
-+# CONFIG_DVB_AU8522_V4L is not set
-+# CONFIG_DVB_TUNER_DIB0070 is not set
-+# CONFIG_DVB_TUNER_DIB0090 is not set
-+
-+#
-+# Tools to develop new frontends
-+#
-+# CONFIG_DVB_DUMMY_FE is not set
-+
-+#
-+# Graphics support
-+#
-+# CONFIG_AGP is not set
-+# CONFIG_VGA_ARB is not set
-+# CONFIG_VGA_SWITCHEROO is not set
-+# CONFIG_DRM is not set
-+# CONFIG_STUB_POULSBO is not set
-+# CONFIG_VGASTATE is not set
-+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-+# CONFIG_FB is not set
-+# CONFIG_EXYNOS_VIDEO is not set
-+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-+
-+#
-+# Console display driver support
-+#
-+# CONFIG_VGA_CONSOLE is not set
-+CONFIG_DUMMY_CONSOLE=y
-+CONFIG_SOUND=m
-+# CONFIG_SOUND_OSS_CORE is not set
-+CONFIG_SND=m
-+# CONFIG_SND_SEQUENCER is not set
-+# CONFIG_SND_MIXER_OSS is not set
-+# CONFIG_SND_PCM_OSS is not set
-+# CONFIG_SND_HRTIMER is not set
-+# CONFIG_SND_RTCTIMER is not set
-+# CONFIG_SND_DYNAMIC_MINORS is not set
-+CONFIG_SND_SUPPORT_OLD_API=y
-+CONFIG_SND_VERBOSE_PROCFS=y
-+# CONFIG_SND_VERBOSE_PRINTK is not set
-+# CONFIG_SND_DEBUG is not set
-+CONFIG_SND_DMA_SGBUF=y
-+# CONFIG_SND_RAWMIDI_SEQ is not set
-+# CONFIG_SND_OPL3_LIB_SEQ is not set
-+# CONFIG_SND_OPL4_LIB_SEQ is not set
-+# CONFIG_SND_SBAWE_SEQ is not set
-+# CONFIG_SND_EMU10K1_SEQ is not set
-+CONFIG_SND_DRIVERS=y
-+# CONFIG_SND_DUMMY is not set
-+# CONFIG_SND_ALOOP is not set
-+# CONFIG_SND_MTPAV is not set
-+# CONFIG_SND_SERIAL_U16550 is not set
-+# CONFIG_SND_MPU401 is not set
-+CONFIG_SND_PCI=y
-+# CONFIG_SND_AD1889 is not set
-+# CONFIG_SND_ALS300 is not set
-+# CONFIG_SND_ALS4000 is not set
-+# CONFIG_SND_ALI5451 is not set
-+# CONFIG_SND_ASIHPI is not set
-+# CONFIG_SND_ATIIXP is not set
-+# CONFIG_SND_ATIIXP_MODEM is not set
-+# CONFIG_SND_AU8810 is not set
-+# CONFIG_SND_AU8820 is not set
-+# CONFIG_SND_AU8830 is not set
-+# CONFIG_SND_AW2 is not set
-+# CONFIG_SND_AZT3328 is not set
-+# CONFIG_SND_BT87X is not set
-+# CONFIG_SND_CA0106 is not set
-+# CONFIG_SND_CMIPCI is not set
-+# CONFIG_SND_OXYGEN is not set
-+# CONFIG_SND_CS4281 is not set
-+# CONFIG_SND_CS46XX is not set
-+# CONFIG_SND_CS5530 is not set
-+# CONFIG_SND_CS5535AUDIO is not set
-+# CONFIG_SND_CTXFI is not set
-+# CONFIG_SND_DARLA20 is not set
-+# CONFIG_SND_GINA20 is not set
-+# CONFIG_SND_LAYLA20 is not set
-+# CONFIG_SND_DARLA24 is not set
-+# CONFIG_SND_GINA24 is not set
-+# CONFIG_SND_LAYLA24 is not set
-+# CONFIG_SND_MONA is not set
-+# CONFIG_SND_MIA is not set
-+# CONFIG_SND_ECHO3G is not set
-+# CONFIG_SND_INDIGO is not set
-+# CONFIG_SND_INDIGOIO is not set
-+# CONFIG_SND_INDIGODJ is not set
-+# CONFIG_SND_INDIGOIOX is not set
-+# CONFIG_SND_INDIGODJX is not set
-+# CONFIG_SND_EMU10K1 is not set
-+# CONFIG_SND_EMU10K1X is not set
-+# CONFIG_SND_ENS1370 is not set
-+# CONFIG_SND_ENS1371 is not set
-+# CONFIG_SND_ES1938 is not set
-+# CONFIG_SND_ES1968 is not set
-+# CONFIG_SND_FM801 is not set
-+# CONFIG_SND_HDA_INTEL is not set
-+# CONFIG_SND_HDSP is not set
-+# CONFIG_SND_HDSPM is not set
-+# CONFIG_SND_ICE1712 is not set
-+# CONFIG_SND_ICE1724 is not set
-+# CONFIG_SND_INTEL8X0 is not set
-+# CONFIG_SND_INTEL8X0M is not set
-+# CONFIG_SND_KORG1212 is not set
-+# CONFIG_SND_LOLA is not set
-+# CONFIG_SND_LX6464ES is not set
-+# CONFIG_SND_MAESTRO3 is not set
-+# CONFIG_SND_MIXART is not set
-+# CONFIG_SND_NM256 is not set
-+# CONFIG_SND_PCXHR is not set
-+# CONFIG_SND_RIPTIDE is not set
-+# CONFIG_SND_RME32 is not set
-+# CONFIG_SND_RME96 is not set
-+# CONFIG_SND_RME9652 is not set
-+# CONFIG_SND_SIS7019 is not set
-+# CONFIG_SND_SONICVIBES is not set
-+# CONFIG_SND_TRIDENT is not set
-+# CONFIG_SND_VIA82XX is not set
-+# CONFIG_SND_VIA82XX_MODEM is not set
-+# CONFIG_SND_VIRTUOSO is not set
-+# CONFIG_SND_VX222 is not set
-+# CONFIG_SND_YMFPCI is not set
-+CONFIG_SND_SPI=y
-+CONFIG_SND_USB=y
-+# CONFIG_SND_USB_AUDIO is not set
-+# CONFIG_SND_USB_UA101 is not set
-+# CONFIG_SND_USB_USX2Y is not set
-+# CONFIG_SND_USB_CAIAQ is not set
-+# CONFIG_SND_USB_US122L is not set
-+# CONFIG_SND_USB_6FIRE is not set
-+# CONFIG_SND_SOC is not set
-+# CONFIG_SOUND_PRIME is not set
-+
-+#
-+# HID support
-+#
-+CONFIG_HID=y
-+# CONFIG_HID_BATTERY_STRENGTH is not set
-+# CONFIG_HIDRAW is not set
-+# CONFIG_UHID is not set
-+CONFIG_HID_GENERIC=y
-+
-+#
-+# Special HID drivers
-+#
-+# CONFIG_HID_A4TECH is not set
-+# CONFIG_HID_ACRUX is not set
-+# CONFIG_HID_APPLE is not set
-+# CONFIG_HID_AUREAL is not set
-+# CONFIG_HID_BELKIN is not set
-+# CONFIG_HID_CHERRY is not set
-+# CONFIG_HID_CHICONY is not set
-+# CONFIG_HID_PRODIKEYS is not set
-+# CONFIG_HID_CYPRESS is not set
-+# CONFIG_HID_DRAGONRISE is not set
-+# CONFIG_HID_EMS_FF is not set
-+# CONFIG_HID_ELECOM is not set
-+# CONFIG_HID_EZKEY is not set
-+# CONFIG_HID_HOLTEK is not set
-+# CONFIG_HID_KEYTOUCH is not set
-+# CONFIG_HID_KYE is not set
-+# CONFIG_HID_UCLOGIC is not set
-+# CONFIG_HID_WALTOP is not set
-+# CONFIG_HID_GYRATION is not set
-+# CONFIG_HID_ICADE is not set
-+# CONFIG_HID_TWINHAN is not set
-+# CONFIG_HID_KENSINGTON is not set
-+# CONFIG_HID_LCPOWER is not set
-+# CONFIG_HID_LENOVO_TPKBD is not set
-+# CONFIG_HID_LOGITECH is not set
-+# CONFIG_HID_MAGICMOUSE is not set
-+# CONFIG_HID_MICROSOFT is not set
-+# CONFIG_HID_MONTEREY is not set
-+# CONFIG_HID_MULTITOUCH is not set
-+# CONFIG_HID_NTRIG is not set
-+# CONFIG_HID_ORTEK is not set
-+# CONFIG_HID_PANTHERLORD is not set
-+# CONFIG_HID_PETALYNX is not set
-+# CONFIG_HID_PICOLCD is not set
-+# CONFIG_HID_PRIMAX is not set
-+# CONFIG_HID_PS3REMOTE is not set
-+# CONFIG_HID_ROCCAT is not set
-+# CONFIG_HID_SAITEK is not set
-+# CONFIG_HID_SAMSUNG is not set
-+# CONFIG_HID_SONY is not set
-+# CONFIG_HID_SPEEDLINK is not set
-+# CONFIG_HID_SUNPLUS is not set
-+# CONFIG_HID_GREENASIA is not set
-+# CONFIG_HID_SMARTJOYPLUS is not set
-+# CONFIG_HID_TIVO is not set
-+# CONFIG_HID_TOPSEED is not set
-+# CONFIG_HID_THRUSTMASTER is not set
-+# CONFIG_HID_WACOM is not set
-+# CONFIG_HID_WIIMOTE is not set
-+# CONFIG_HID_ZEROPLUS is not set
-+# CONFIG_HID_ZYDACRON is not set
-+CONFIG_HID_SENSOR_HUB=m
-+
-+#
-+# USB HID support
-+#
-+CONFIG_USB_HID=m
-+# CONFIG_HID_PID is not set
-+# CONFIG_USB_HIDDEV is not set
-+
-+#
-+# USB HID Boot Protocol drivers
-+#
-+# CONFIG_USB_KBD is not set
-+# CONFIG_USB_MOUSE is not set
-+
-+#
-+# I2C HID support
-+#
-+# CONFIG_I2C_HID is not set
-+CONFIG_USB_ARCH_HAS_OHCI=y
-+CONFIG_USB_ARCH_HAS_EHCI=y
-+CONFIG_USB_ARCH_HAS_XHCI=y
-+CONFIG_USB_SUPPORT=y
-+CONFIG_USB_COMMON=m
-+CONFIG_USB_ARCH_HAS_HCD=y
-+CONFIG_USB=m
-+# CONFIG_USB_DEBUG is not set
-+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
-+
-+#
-+# Miscellaneous USB options
-+#
-+# CONFIG_USB_DYNAMIC_MINORS is not set
-+# CONFIG_USB_SUSPEND is not set
-+# CONFIG_USB_OTG_WHITELIST is not set
-+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
-+# CONFIG_USB_DWC3 is not set
-+# CONFIG_USB_MON is not set
-+# CONFIG_USB_WUSB_CBAF is not set
-+
-+#
-+# USB Host Controller Drivers
-+#
-+# CONFIG_USB_C67X00_HCD is not set
-+# CONFIG_USB_XHCI_HCD is not set
-+CONFIG_USB_EHCI_HCD=m
-+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-+CONFIG_USB_EHCI_TT_NEWSCHED=y
-+CONFIG_USB_EHCI_PCI=m
-+# CONFIG_USB_OXU210HP_HCD is not set
-+# CONFIG_USB_ISP116X_HCD is not set
-+# CONFIG_USB_ISP1760_HCD is not set
-+# CONFIG_USB_ISP1362_HCD is not set
-+CONFIG_USB_OHCI_HCD=m
-+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
-+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
-+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
-+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
-+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-+CONFIG_USB_UHCI_HCD=m
-+# CONFIG_USB_SL811_HCD is not set
-+# CONFIG_USB_R8A66597_HCD is not set
-+# CONFIG_USB_MUSB_HDRC is not set
-+# CONFIG_USB_CHIPIDEA is not set
-+# CONFIG_USB_RENESAS_USBHS is not set
-+
-+#
-+# USB Device Class drivers
-+#
-+CONFIG_USB_ACM=m
-+# CONFIG_USB_PRINTER is not set
-+# CONFIG_USB_WDM is not set
-+# CONFIG_USB_TMC is not set
-+
-+#
-+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
-+#
-+
-+#
-+# also be needed; see USB_STORAGE Help for more info
-+#
-+CONFIG_USB_STORAGE=m
-+# CONFIG_USB_STORAGE_DEBUG is not set
-+# CONFIG_USB_STORAGE_REALTEK is not set
-+# CONFIG_USB_STORAGE_DATAFAB is not set
-+# CONFIG_USB_STORAGE_FREECOM is not set
-+# CONFIG_USB_STORAGE_ISD200 is not set
-+# CONFIG_USB_STORAGE_USBAT is not set
-+# CONFIG_USB_STORAGE_SDDR09 is not set
-+# CONFIG_USB_STORAGE_SDDR55 is not set
-+# CONFIG_USB_STORAGE_JUMPSHOT is not set
-+# CONFIG_USB_STORAGE_ALAUDA is not set
-+# CONFIG_USB_STORAGE_ONETOUCH is not set
-+# CONFIG_USB_STORAGE_KARMA is not set
-+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
-+# CONFIG_USB_STORAGE_ENE_UB6250 is not set
-+
-+#
-+# USB Imaging devices
-+#
-+# CONFIG_USB_MDC800 is not set
-+# CONFIG_USB_MICROTEK is not set
-+
-+#
-+# USB port drivers
-+#
-+CONFIG_USB_SERIAL=m
-+# CONFIG_USB_SERIAL_GENERIC is not set
-+# CONFIG_USB_SERIAL_AIRCABLE is not set
-+# CONFIG_USB_SERIAL_ARK3116 is not set
-+# CONFIG_USB_SERIAL_BELKIN is not set
-+# CONFIG_USB_SERIAL_CH341 is not set
-+# CONFIG_USB_SERIAL_WHITEHEAT is not set
-+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-+# CONFIG_USB_SERIAL_CP210X is not set
-+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
-+# CONFIG_USB_SERIAL_EMPEG is not set
-+# CONFIG_USB_SERIAL_FTDI_SIO is not set
-+# CONFIG_USB_SERIAL_FUNSOFT is not set
-+# CONFIG_USB_SERIAL_VISOR is not set
-+# CONFIG_USB_SERIAL_IPAQ is not set
-+# CONFIG_USB_SERIAL_IR is not set
-+# CONFIG_USB_SERIAL_EDGEPORT is not set
-+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-+# CONFIG_USB_SERIAL_F81232 is not set
-+# CONFIG_USB_SERIAL_GARMIN is not set
-+# CONFIG_USB_SERIAL_IPW is not set
-+# CONFIG_USB_SERIAL_IUU is not set
-+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-+# CONFIG_USB_SERIAL_KEYSPAN is not set
-+# CONFIG_USB_SERIAL_KLSI is not set
-+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
-+# CONFIG_USB_SERIAL_MCT_U232 is not set
-+# CONFIG_USB_SERIAL_METRO is not set
-+# CONFIG_USB_SERIAL_MOS7720 is not set
-+# CONFIG_USB_SERIAL_MOS7840 is not set
-+# CONFIG_USB_SERIAL_MOTOROLA is not set
-+# CONFIG_USB_SERIAL_NAVMAN is not set
-+CONFIG_USB_SERIAL_PL2303=m
-+# CONFIG_USB_SERIAL_OTI6858 is not set
-+# CONFIG_USB_SERIAL_QCAUX is not set
-+# CONFIG_USB_SERIAL_QUALCOMM is not set
-+# CONFIG_USB_SERIAL_SPCP8X5 is not set
-+# CONFIG_USB_SERIAL_HP4X is not set
-+# CONFIG_USB_SERIAL_SAFE is not set
-+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
-+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
-+# CONFIG_USB_SERIAL_SYMBOL is not set
-+# CONFIG_USB_SERIAL_TI is not set
-+# CONFIG_USB_SERIAL_CYBERJACK is not set
-+# CONFIG_USB_SERIAL_XIRCOM is not set
-+# CONFIG_USB_SERIAL_OPTION is not set
-+# CONFIG_USB_SERIAL_OMNINET is not set
-+# CONFIG_USB_SERIAL_OPTICON is not set
-+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
-+# CONFIG_USB_SERIAL_ZIO is not set
-+# CONFIG_USB_SERIAL_ZTE is not set
-+# CONFIG_USB_SERIAL_SSU100 is not set
-+# CONFIG_USB_SERIAL_QT2 is not set
-+# CONFIG_USB_SERIAL_DEBUG is not set
-+
-+#
-+# USB Miscellaneous drivers
-+#
-+# CONFIG_USB_EMI62 is not set
-+# CONFIG_USB_EMI26 is not set
-+# CONFIG_USB_ADUTUX is not set
-+# CONFIG_USB_SEVSEG is not set
-+# CONFIG_USB_RIO500 is not set
-+# CONFIG_USB_LEGOTOWER is not set
-+# CONFIG_USB_LCD is not set
-+# CONFIG_USB_LED is not set
-+# CONFIG_USB_CYPRESS_CY7C63 is not set
-+# CONFIG_USB_CYTHERM is not set
-+# CONFIG_USB_IDMOUSE is not set
-+# CONFIG_USB_FTDI_ELAN is not set
-+# CONFIG_USB_APPLEDISPLAY is not set
-+# CONFIG_USB_SISUSBVGA is not set
-+# CONFIG_USB_LD is not set
-+# CONFIG_USB_TRANCEVIBRATOR is not set
-+# CONFIG_USB_IOWARRIOR is not set
-+# CONFIG_USB_TEST is not set
-+# CONFIG_USB_ISIGHTFW is not set
-+# CONFIG_USB_YUREX is not set
-+# CONFIG_USB_EZUSB_FX2 is not set
-+
-+#
-+# USB Physical Layer drivers
-+#
-+# CONFIG_USB_ISP1301 is not set
-+# CONFIG_USB_RCAR_PHY is not set
-+CONFIG_USB_GADGET=m
-+# CONFIG_USB_GADGET_DEBUG is not set
-+# CONFIG_USB_GADGET_DEBUG_FILES is not set
-+# CONFIG_USB_GADGET_DEBUG_FS is not set
-+CONFIG_USB_GADGET_VBUS_DRAW=2
-+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
-+
-+#
-+# USB Peripheral Controller
-+#
-+# CONFIG_USB_R8A66597 is not set
-+# CONFIG_USB_MV_UDC is not set
-+# CONFIG_USB_M66592 is not set
-+# CONFIG_USB_AMD5536UDC is not set
-+# CONFIG_USB_NET2272 is not set
-+# CONFIG_USB_NET2280 is not set
-+# CONFIG_USB_GOKU is not set
-+CONFIG_USB_EG20T=m
-+# CONFIG_USB_DUMMY_HCD is not set
-+CONFIG_USB_LIBCOMPOSITE=m
-+CONFIG_USB_ZERO=m
-+# CONFIG_USB_AUDIO is not set
-+CONFIG_USB_ETH=m
-+CONFIG_USB_ETH_RNDIS=y
-+# CONFIG_USB_ETH_EEM is not set
-+# CONFIG_USB_G_NCM is not set
-+# CONFIG_USB_GADGETFS is not set
-+# CONFIG_USB_FUNCTIONFS is not set
-+CONFIG_USB_MASS_STORAGE=m
-+CONFIG_USB_G_SERIAL=m
-+# CONFIG_USB_MIDI_GADGET is not set
-+# CONFIG_USB_G_PRINTER is not set
-+# CONFIG_USB_CDC_COMPOSITE is not set
-+# CONFIG_USB_G_ACM_MS is not set
-+# CONFIG_USB_G_MULTI is not set
-+# CONFIG_USB_G_HID is not set
-+# CONFIG_USB_G_DBGP is not set
-+# CONFIG_USB_G_WEBCAM is not set
-+
-+#
-+# OTG and related infrastructure
-+#
-+# CONFIG_USB_GPIO_VBUS is not set
-+# CONFIG_NOP_USB_XCEIV is not set
-+# CONFIG_UWB is not set
-+CONFIG_MMC=m
-+# CONFIG_MMC_DEBUG is not set
-+# CONFIG_MMC_UNSAFE_RESUME is not set
-+# CONFIG_MMC_CLKGATE is not set
-+
-+#
-+# MMC/SD/SDIO Card Drivers
-+#
-+CONFIG_MMC_BLOCK=m
-+CONFIG_MMC_BLOCK_MINORS=8
-+CONFIG_MMC_BLOCK_BOUNCE=y
-+# CONFIG_SDIO_UART is not set
-+# CONFIG_MMC_TEST is not set
-+
-+#
-+# MMC/SD/SDIO Host Controller Drivers
-+#
-+CONFIG_MMC_SDHCI=m
-+CONFIG_MMC_SDHCI_PCI=m
-+# CONFIG_MMC_RICOH_MMC is not set
-+# CONFIG_MMC_SDHCI_ACPI is not set
-+CONFIG_MMC_SDHCI_PLTFM=m
-+# CONFIG_MMC_WBSD is not set
-+# CONFIG_MMC_TIFM_SD is not set
-+# CONFIG_MMC_CB710 is not set
-+# CONFIG_MMC_VIA_SDMMC is not set
-+# CONFIG_MMC_VUB300 is not set
-+# CONFIG_MMC_USHC is not set
-+# CONFIG_MEMSTICK is not set
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=m
-+
-+#
-+# LED drivers
-+#
-+# CONFIG_LEDS_LM3530 is not set
-+# CONFIG_LEDS_LM3642 is not set
-+# CONFIG_LEDS_PCA9532 is not set
-+# CONFIG_LEDS_GPIO is not set
-+# CONFIG_LEDS_LP3944 is not set
-+# CONFIG_LEDS_LP5521 is not set
-+# CONFIG_LEDS_LP5523 is not set
-+# CONFIG_LEDS_PCA955X is not set
-+# CONFIG_LEDS_PCA9633 is not set
-+# CONFIG_LEDS_DAC124S085 is not set
-+# CONFIG_LEDS_BD2802 is not set
-+# CONFIG_LEDS_LT3593 is not set
-+# CONFIG_LEDS_TCA6507 is not set
-+# CONFIG_LEDS_LM355x is not set
-+# CONFIG_LEDS_OT200 is not set
-+# CONFIG_LEDS_BLINKM is not set
-+CONFIG_LEDS_TRIGGERS=y
-+
-+#
-+# LED Triggers
-+#
-+# CONFIG_LEDS_TRIGGER_TIMER is not set
-+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
-+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
-+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
-+# CONFIG_LEDS_TRIGGER_CPU is not set
-+# CONFIG_LEDS_TRIGGER_GPIO is not set
-+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
-+
-+#
-+# iptables trigger is under Netfilter config (LED target)
-+#
-+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
-+# CONFIG_ACCESSIBILITY is not set
-+# CONFIG_INFINIBAND is not set
-+# CONFIG_EDAC is not set
-+# CONFIG_RTC_CLASS is not set
-+CONFIG_DMADEVICES=y
-+# CONFIG_DMADEVICES_DEBUG is not set
-+
-+#
-+# DMA Devices
-+#
-+CONFIG_INTEL_MID_DMAC=m
-+CONFIG_INTEL_MID_PCI=m
-+CONFIG_INTEL_CLN_DMAC=m
-+# CONFIG_INTEL_IOATDMA is not set
-+# CONFIG_TIMB_DMA is not set
-+# CONFIG_PCH_DMA is not set
-+CONFIG_DMA_ENGINE=y
-+
-+#
-+# DMA Clients
-+#
-+# CONFIG_NET_DMA is not set
-+# CONFIG_ASYNC_TX_DMA is not set
-+# CONFIG_DMATEST is not set
-+# CONFIG_AUXDISPLAY is not set
-+CONFIG_UIO=m
-+# CONFIG_UIO_CIF is not set
-+# CONFIG_UIO_PDRV is not set
-+# CONFIG_UIO_PDRV_GENIRQ is not set
-+# CONFIG_UIO_DMEM_GENIRQ is not set
-+# CONFIG_UIO_AEC is not set
-+# CONFIG_UIO_SERCOS3 is not set
-+# CONFIG_UIO_PCI_GENERIC is not set
-+# CONFIG_UIO_NETX is not set
-+
-+#
-+# Virtio drivers
-+#
-+# CONFIG_VIRTIO_PCI is not set
-+# CONFIG_VIRTIO_MMIO is not set
-+
-+#
-+# Microsoft Hyper-V guest support
-+#
-+# CONFIG_HYPERV is not set
-+CONFIG_STAGING=y
-+# CONFIG_ET131X is not set
-+# CONFIG_SLICOSS is not set
-+# CONFIG_USBIP_CORE is not set
-+# CONFIG_W35UND is not set
-+# CONFIG_PRISM2_USB is not set
-+# CONFIG_ECHO is not set
-+# CONFIG_COMEDI is not set
-+# CONFIG_ASUS_OLED is not set
-+# CONFIG_R8187SE is not set
-+# CONFIG_RTL8192U is not set
-+# CONFIG_RTLLIB is not set
-+# CONFIG_R8712U is not set
-+# CONFIG_RTS5139 is not set
-+# CONFIG_TRANZPORT is not set
-+# CONFIG_LINE6_USB is not set
-+# CONFIG_USB_SERIAL_QUATECH2 is not set
-+# CONFIG_VT6655 is not set
-+# CONFIG_VT6656 is not set
-+# CONFIG_DX_SEP is not set
-+
-+#
-+# IIO staging drivers
-+#
-+# CONFIG_IIO_SW_RING is not set
-+
-+#
-+# Accelerometers
-+#
-+# CONFIG_ADIS16201 is not set
-+# CONFIG_ADIS16203 is not set
-+# CONFIG_ADIS16204 is not set
-+# CONFIG_ADIS16209 is not set
-+# CONFIG_ADIS16220 is not set
-+# CONFIG_ADIS16240 is not set
-+# CONFIG_KXSD9 is not set
-+# CONFIG_LIS3L02DQ is not set
-+# CONFIG_SCA3000 is not set
-+
-+#
-+# Analog to digital converters
-+#
-+# CONFIG_AD7291 is not set
-+# CONFIG_AD7606 is not set
-+# CONFIG_AD799X is not set
-+# CONFIG_AD7780 is not set
-+# CONFIG_AD7816 is not set
-+# CONFIG_AD7192 is not set
-+# CONFIG_ADT7410 is not set
-+# CONFIG_AD7280 is not set
-+CONFIG_MAX78M6610_LMU=m
-+
-+#
-+# Analog digital bi-direction converters
-+#
-+# CONFIG_ADT7316 is not set
-+
-+#
-+# Capacitance to digital converters
-+#
-+# CONFIG_AD7150 is not set
-+# CONFIG_AD7152 is not set
-+# CONFIG_AD7746 is not set
-+
-+#
-+# Direct Digital Synthesis
-+#
-+# CONFIG_AD5930 is not set
-+# CONFIG_AD9832 is not set
-+# CONFIG_AD9834 is not set
-+# CONFIG_AD9850 is not set
-+# CONFIG_AD9852 is not set
-+# CONFIG_AD9910 is not set
-+# CONFIG_AD9951 is not set
-+
-+#
-+# Digital gyroscope sensors
-+#
-+# CONFIG_ADIS16060 is not set
-+# CONFIG_ADIS16080 is not set
-+# CONFIG_ADIS16130 is not set
-+# CONFIG_ADIS16260 is not set
-+# CONFIG_ADXRS450 is not set
-+
-+#
-+# Network Analyzer, Impedance Converters
-+#
-+# CONFIG_AD5933 is not set
-+
-+#
-+# Inertial measurement units
-+#
-+# CONFIG_ADIS16400 is not set
-+
-+#
-+# Light sensors
-+#
-+# CONFIG_SENSORS_ISL29018 is not set
-+# CONFIG_SENSORS_ISL29028 is not set
-+# CONFIG_SENSORS_TSL2563 is not set
-+# CONFIG_TSL2583 is not set
-+# CONFIG_TSL2x7x is not set
-+
-+#
-+# Magnetometer sensors
-+#
-+# CONFIG_SENSORS_AK8975 is not set
-+# CONFIG_SENSORS_HMC5843 is not set
-+
-+#
-+# Active energy metering IC
-+#
-+# CONFIG_ADE7753 is not set
-+# CONFIG_ADE7754 is not set
-+# CONFIG_ADE7758 is not set
-+# CONFIG_ADE7759 is not set
-+# CONFIG_ADE7854 is not set
-+
-+#
-+# Resolver to digital converters
-+#
-+# CONFIG_AD2S90 is not set
-+# CONFIG_AD2S1200 is not set
-+# CONFIG_AD2S1210 is not set
-+
-+#
-+# Triggers - standalone
-+#
-+# CONFIG_IIO_GPIO_TRIGGER is not set
-+CONFIG_IIO_SYSFS_TRIGGER=m
-+CONFIG_IIO_HRTIMER_TRIGGER=m
-+# CONFIG_IIO_SIMPLE_DUMMY is not set
-+# CONFIG_ZSMALLOC is not set
-+# CONFIG_CRYSTALHD is not set
-+# CONFIG_ACPI_QUICKSTART is not set
-+# CONFIG_USB_ENESTORAGE is not set
-+# CONFIG_BCM_WIMAX is not set
-+# CONFIG_FT1000 is not set
-+
-+#
-+# Speakup console speech
-+#
-+# CONFIG_SPEAKUP is not set
-+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
-+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
-+# CONFIG_STAGING_MEDIA is not set
-+
-+#
-+# Android
-+#
-+# CONFIG_ANDROID is not set
-+# CONFIG_USB_WPAN_HCD is not set
-+# CONFIG_WIMAX_GDM72XX is not set
-+# CONFIG_CSR_WIFI is not set
-+# CONFIG_NET_VENDOR_SILICOM is not set
-+# CONFIG_CED1401 is not set
-+# CONFIG_DGRP is not set
-+# CONFIG_SB105X is not set
-+CONFIG_X86_PLATFORM_DEVICES=y
-+# CONFIG_ACERHDF is not set
-+# CONFIG_ASUS_LAPTOP is not set
-+# CONFIG_FUJITSU_TABLET is not set
-+# CONFIG_AMILO_RFKILL is not set
-+# CONFIG_HP_ACCEL is not set
-+# CONFIG_SONY_LAPTOP is not set
-+# CONFIG_THINKPAD_ACPI is not set
-+# CONFIG_SENSORS_HDAPS is not set
-+# CONFIG_INTEL_MENLOW is not set
-+# CONFIG_ACPI_WMI is not set
-+# CONFIG_TOPSTAR_LAPTOP is not set
-+# CONFIG_TOSHIBA_BT_RFKILL is not set
-+# CONFIG_ACPI_CMPC is not set
-+CONFIG_INTEL_CLN_ESRAM=y
-+CONFIG_INTEL_CLN_ECC_REFRESH_PERIOD=24
-+CONFIG_INTEL_CLN_ECC_SCRUB=y
-+# CONFIG_INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG is not set
-+# CONFIG_INTEL_CLN_ECC_SCRUB_S3_CONFIG is not set
-+CONFIG_INTEL_CLN_THERMAL=y
-+CONFIG_INTEL_CLN_AUDIO_CTRL=m
-+# CONFIG_INTEL_IPS is not set
-+# CONFIG_IBM_RTL is not set
-+# CONFIG_XO15_EBOOK is not set
-+
-+#
-+# Hardware Spinlock drivers
-+#
-+CONFIG_CLKSRC_I8253=y
-+CONFIG_CLKEVT_I8253=y
-+CONFIG_CLKBLD_I8253=y
-+# CONFIG_IOMMU_SUPPORT is not set
-+
-+#
-+# Remoteproc drivers (EXPERIMENTAL)
-+#
-+# CONFIG_STE_MODEM_RPROC is not set
-+
-+#
-+# Rpmsg drivers (EXPERIMENTAL)
-+#
-+# CONFIG_VIRT_DRIVERS is not set
-+# CONFIG_PM_DEVFREQ is not set
-+# CONFIG_EXTCON is not set
-+# CONFIG_MEMORY is not set
-+CONFIG_IIO=m
-+CONFIG_IIO_BUFFER=y
-+CONFIG_IIO_BUFFER_CB=y
-+CONFIG_IIO_KFIFO_BUF=m
-+CONFIG_IIO_TRIGGERED_BUFFER=m
-+CONFIG_IIO_TRIGGER=y
-+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
-+
-+#
-+# Accelerometers
-+#
-+CONFIG_HID_SENSOR_ACCEL_3D=m
-+
-+#
-+# Analog to digital converters
-+#
-+# CONFIG_AD7266 is not set
-+CONFIG_AD7298=m
-+# CONFIG_AD7791 is not set
-+# CONFIG_AD7793 is not set
-+# CONFIG_AD7476 is not set
-+# CONFIG_AD7887 is not set
-+# CONFIG_MAX1363 is not set
-+# CONFIG_TI_ADC081C is not set
-+
-+#
-+# Amplifiers
-+#
-+# CONFIG_AD8366 is not set
-+
-+#
-+# STMicro sensors
-+#
-+CONFIG_IIO_ST_SENSORS_I2C=m
-+CONFIG_IIO_ST_SENSORS_SPI=m
-+CONFIG_IIO_ST_SENSORS_CORE=m
-+
-+#
-+# Digital to analog converters
-+#
-+# CONFIG_AD5064 is not set
-+# CONFIG_AD5360 is not set
-+# CONFIG_AD5380 is not set
-+# CONFIG_AD5421 is not set
-+# CONFIG_AD5624R_SPI is not set
-+# CONFIG_AD5446 is not set
-+# CONFIG_AD5449 is not set
-+# CONFIG_AD5504 is not set
-+# CONFIG_AD5755 is not set
-+# CONFIG_AD5764 is not set
-+# CONFIG_AD5791 is not set
-+# CONFIG_AD5686 is not set
-+# CONFIG_MAX517 is not set
-+# CONFIG_MCP4725 is not set
-+
-+#
-+# Frequency Synthesizers DDS/PLL
-+#
-+
-+#
-+# Clock Generator/Distribution
-+#
-+# CONFIG_AD9523 is not set
-+
-+#
-+# Phase-Locked Loop (PLL) frequency synthesizers
-+#
-+# CONFIG_ADF4350 is not set
-+
-+#
-+# Digital gyroscope sensors
-+#
-+# CONFIG_ADIS16136 is not set
-+# CONFIG_HID_SENSOR_GYRO_3D is not set
-+
-+#
-+# Inertial measurement units
-+#
-+# CONFIG_ADIS16480 is not set
-+
-+#
-+# Light sensors
-+#
-+# CONFIG_ADJD_S311 is not set
-+# CONFIG_VCNL4000 is not set
-+# CONFIG_HID_SENSOR_ALS is not set
-+
-+#
-+# Magnetometer sensors
-+#
-+# CONFIG_HID_SENSOR_MAGNETOMETER_3D is not set
-+# CONFIG_VME_BUS is not set
-+CONFIG_PWM=y
-+CONFIG_PWM_SYSFS=y
-+# CONFIG_IPACK_BUS is not set
-+
-+#
-+# Firmware Drivers
-+#
-+# CONFIG_EDD is not set
-+CONFIG_FIRMWARE_MEMMAP=y
-+CONFIG_EFI_VARS=m
-+# CONFIG_DELL_RBU is not set
-+# CONFIG_DCDBAS is not set
-+# CONFIG_ISCSI_IBFT_FIND is not set
-+# CONFIG_GOOGLE_FIRMWARE is not set
-+
-+#
-+# File systems
-+#
-+CONFIG_DCACHE_WORD_ACCESS=y
-+CONFIG_EXT2_FS=y
-+# CONFIG_EXT2_FS_XATTR is not set
-+# CONFIG_EXT2_FS_XIP is not set
-+CONFIG_EXT3_FS=y
-+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-+CONFIG_EXT3_FS_XATTR=y
-+CONFIG_EXT3_FS_POSIX_ACL=y
-+CONFIG_EXT3_FS_SECURITY=y
-+# CONFIG_EXT4_FS is not set
-+CONFIG_JBD=y
-+# CONFIG_JBD_DEBUG is not set
-+CONFIG_FS_MBCACHE=y
-+# CONFIG_REISERFS_FS is not set
-+# CONFIG_JFS_FS is not set
-+# CONFIG_XFS_FS is not set
-+# CONFIG_BTRFS_FS is not set
-+# CONFIG_NILFS2_FS is not set
-+CONFIG_FS_POSIX_ACL=y
-+CONFIG_FILE_LOCKING=y
-+CONFIG_FSNOTIFY=y
-+CONFIG_DNOTIFY=y
-+CONFIG_INOTIFY_USER=y
-+# CONFIG_FANOTIFY is not set
-+# CONFIG_QUOTA is not set
-+# CONFIG_QUOTACTL is not set
-+# CONFIG_AUTOFS4_FS is not set
-+# CONFIG_FUSE_FS is not set
-+CONFIG_GENERIC_ACL=y
-+
-+#
-+# Caches
-+#
-+# CONFIG_FSCACHE is not set
-+
-+#
-+# CD-ROM/DVD Filesystems
-+#
-+# CONFIG_ISO9660_FS is not set
-+# CONFIG_UDF_FS is not set
-+
-+#
-+# DOS/FAT/NT Filesystems
-+#
-+CONFIG_FAT_FS=y
-+# CONFIG_MSDOS_FS is not set
-+CONFIG_VFAT_FS=y
-+CONFIG_FAT_DEFAULT_CODEPAGE=437
-+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-+# CONFIG_NTFS_FS is not set
-+
-+#
-+# Pseudo filesystems
-+#
-+CONFIG_PROC_FS=y
-+CONFIG_PROC_KCORE=y
-+CONFIG_PROC_SYSCTL=y
-+CONFIG_PROC_PAGE_MONITOR=y
-+CONFIG_SYSFS=y
-+CONFIG_TMPFS=y
-+CONFIG_TMPFS_POSIX_ACL=y
-+CONFIG_TMPFS_XATTR=y
-+CONFIG_HUGETLBFS=y
-+CONFIG_HUGETLB_PAGE=y
-+# CONFIG_CONFIGFS_FS is not set
-+# CONFIG_MISC_FILESYSTEMS is not set
-+CONFIG_NETWORK_FILESYSTEMS=y
-+# CONFIG_NFS_FS is not set
-+# CONFIG_NFSD is not set
-+# CONFIG_CEPH_FS is not set
-+# CONFIG_CIFS is not set
-+# CONFIG_NCP_FS is not set
-+# CONFIG_CODA_FS is not set
-+# CONFIG_AFS_FS is not set
-+CONFIG_NLS=y
-+CONFIG_NLS_DEFAULT="utf8"
-+CONFIG_NLS_CODEPAGE_437=y
-+# CONFIG_NLS_CODEPAGE_737 is not set
-+# CONFIG_NLS_CODEPAGE_775 is not set
-+CONFIG_NLS_CODEPAGE_850=y
-+# CONFIG_NLS_CODEPAGE_852 is not set
-+# CONFIG_NLS_CODEPAGE_855 is not set
-+# CONFIG_NLS_CODEPAGE_857 is not set
-+# CONFIG_NLS_CODEPAGE_860 is not set
-+# CONFIG_NLS_CODEPAGE_861 is not set
-+# CONFIG_NLS_CODEPAGE_862 is not set
-+# CONFIG_NLS_CODEPAGE_863 is not set
-+# CONFIG_NLS_CODEPAGE_864 is not set
-+# CONFIG_NLS_CODEPAGE_865 is not set
-+# CONFIG_NLS_CODEPAGE_866 is not set
-+# CONFIG_NLS_CODEPAGE_869 is not set
-+# CONFIG_NLS_CODEPAGE_936 is not set
-+# CONFIG_NLS_CODEPAGE_950 is not set
-+# CONFIG_NLS_CODEPAGE_932 is not set
-+# CONFIG_NLS_CODEPAGE_949 is not set
-+# CONFIG_NLS_CODEPAGE_874 is not set
-+# CONFIG_NLS_ISO8859_8 is not set
-+# CONFIG_NLS_CODEPAGE_1250 is not set
-+# CONFIG_NLS_CODEPAGE_1251 is not set
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=y
-+# CONFIG_NLS_ISO8859_2 is not set
-+# CONFIG_NLS_ISO8859_3 is not set
-+# CONFIG_NLS_ISO8859_4 is not set
-+# CONFIG_NLS_ISO8859_5 is not set
-+# CONFIG_NLS_ISO8859_6 is not set
-+# CONFIG_NLS_ISO8859_7 is not set
-+# CONFIG_NLS_ISO8859_9 is not set
-+# CONFIG_NLS_ISO8859_13 is not set
-+# CONFIG_NLS_ISO8859_14 is not set
-+# CONFIG_NLS_ISO8859_15 is not set
-+# CONFIG_NLS_KOI8_R is not set
-+# CONFIG_NLS_KOI8_U is not set
-+# CONFIG_NLS_MAC_ROMAN is not set
-+# CONFIG_NLS_MAC_CELTIC is not set
-+# CONFIG_NLS_MAC_CENTEURO is not set
-+# CONFIG_NLS_MAC_CROATIAN is not set
-+# CONFIG_NLS_MAC_CYRILLIC is not set
-+# CONFIG_NLS_MAC_GAELIC is not set
-+# CONFIG_NLS_MAC_GREEK is not set
-+# CONFIG_NLS_MAC_ICELAND is not set
-+# CONFIG_NLS_MAC_INUIT is not set
-+# CONFIG_NLS_MAC_ROMANIAN is not set
-+# CONFIG_NLS_MAC_TURKISH is not set
-+# CONFIG_NLS_UTF8 is not set
-+
-+#
-+# Kernel hacking
-+#
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-+CONFIG_PRINTK_TIME=y
-+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
-+# CONFIG_ENABLE_WARN_DEPRECATED is not set
-+CONFIG_ENABLE_MUST_CHECK=y
-+CONFIG_FRAME_WARN=2048
-+CONFIG_MAGIC_SYSRQ=y
-+# CONFIG_STRIP_ASM_SYMS is not set
-+# CONFIG_READABLE_ASM is not set
-+# CONFIG_UNUSED_SYMBOLS is not set
-+CONFIG_DEBUG_FS=y
-+CONFIG_HEADERS_CHECK=y
-+# CONFIG_DEBUG_SECTION_MISMATCH is not set
-+CONFIG_DEBUG_KERNEL=y
-+# CONFIG_DEBUG_SHIRQ is not set
-+# CONFIG_LOCKUP_DETECTOR is not set
-+# CONFIG_PANIC_ON_OOPS is not set
-+CONFIG_PANIC_ON_OOPS_VALUE=0
-+# CONFIG_DETECT_HUNG_TASK is not set
-+# CONFIG_SCHED_DEBUG is not set
-+# CONFIG_SCHEDSTATS is not set
-+CONFIG_TIMER_STATS=y
-+# CONFIG_DEBUG_OBJECTS is not set
-+# CONFIG_SLUB_DEBUG_ON is not set
-+# CONFIG_SLUB_STATS is not set
-+CONFIG_HAVE_DEBUG_KMEMLEAK=y
-+# CONFIG_DEBUG_KMEMLEAK is not set
-+# CONFIG_DEBUG_RT_MUTEXES is not set
-+# CONFIG_RT_MUTEX_TESTER is not set
-+CONFIG_DEBUG_SPINLOCK=y
-+CONFIG_DEBUG_MUTEXES=y
-+CONFIG_DEBUG_LOCK_ALLOC=y
-+CONFIG_PROVE_LOCKING=y
-+# CONFIG_PROVE_RCU is not set
-+# CONFIG_SPARSE_RCU_POINTER is not set
-+CONFIG_LOCKDEP=y
-+# CONFIG_LOCK_STAT is not set
-+# CONFIG_DEBUG_LOCKDEP is not set
-+CONFIG_TRACE_IRQFLAGS=y
-+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
-+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-+CONFIG_STACKTRACE=y
-+# CONFIG_DEBUG_STACK_USAGE is not set
-+# CONFIG_DEBUG_KOBJECT is not set
-+# CONFIG_DEBUG_HIGHMEM is not set
-+CONFIG_DEBUG_BUGVERBOSE=y
-+# CONFIG_DEBUG_INFO is not set
-+# CONFIG_DEBUG_VM is not set
-+# CONFIG_DEBUG_VIRTUAL is not set
-+# CONFIG_DEBUG_WRITECOUNT is not set
-+CONFIG_DEBUG_MEMORY_INIT=y
-+# CONFIG_DEBUG_LIST is not set
-+# CONFIG_TEST_LIST_SORT is not set
-+# CONFIG_DEBUG_SG is not set
-+# CONFIG_DEBUG_NOTIFIERS is not set
-+# CONFIG_DEBUG_CREDENTIALS is not set
-+CONFIG_ARCH_WANT_FRAME_POINTERS=y
-+CONFIG_FRAME_POINTER=y
-+# CONFIG_BOOT_PRINTK_DELAY is not set
-+# CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_RCU_TRACE is not set
-+# CONFIG_BACKTRACE_SELF_TEST is not set
-+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
-+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
-+# CONFIG_LKDTM is not set
-+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
-+# CONFIG_FAULT_INJECTION is not set
-+# CONFIG_LATENCYTOP is not set
-+# CONFIG_DEBUG_PAGEALLOC is not set
-+CONFIG_USER_STACKTRACE_SUPPORT=y
-+CONFIG_HAVE_FUNCTION_TRACER=y
-+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
-+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
-+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
-+CONFIG_HAVE_DYNAMIC_FTRACE=y
-+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
-+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
-+CONFIG_HAVE_C_RECORDMCOUNT=y
-+CONFIG_TRACING_SUPPORT=y
-+# CONFIG_FTRACE is not set
-+# CONFIG_RBTREE_TEST is not set
-+# CONFIG_INTERVAL_TREE_TEST is not set
-+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
-+# CONFIG_BUILD_DOCSRC is not set
-+# CONFIG_DYNAMIC_DEBUG is not set
-+# CONFIG_DMA_API_DEBUG is not set
-+# CONFIG_ATOMIC64_SELFTEST is not set
-+# CONFIG_SAMPLES is not set
-+CONFIG_HAVE_ARCH_KGDB=y
-+# CONFIG_KGDB is not set
-+CONFIG_HAVE_ARCH_KMEMCHECK=y
-+# CONFIG_KMEMCHECK is not set
-+# CONFIG_TEST_KSTRTOX is not set
-+# CONFIG_STRICT_DEVMEM is not set
-+CONFIG_X86_VERBOSE_BOOTUP=y
-+CONFIG_EARLY_PRINTK=y
-+# CONFIG_EARLY_PRINTK_DBGP is not set
-+CONFIG_DEBUG_STACKOVERFLOW=y
-+CONFIG_X86_PTDUMP=y
-+CONFIG_DEBUG_RODATA=y
-+# CONFIG_DEBUG_RODATA_TEST is not set
-+CONFIG_DEBUG_SET_MODULE_RONX=y
-+# CONFIG_DEBUG_NX_TEST is not set
-+# CONFIG_DOUBLEFAULT is not set
-+# CONFIG_IOMMU_STRESS is not set
-+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
-+CONFIG_IO_DELAY_TYPE_0X80=0
-+CONFIG_IO_DELAY_TYPE_0XED=1
-+CONFIG_IO_DELAY_TYPE_UDELAY=2
-+CONFIG_IO_DELAY_TYPE_NONE=3
-+CONFIG_IO_DELAY_0X80=y
-+# CONFIG_IO_DELAY_0XED is not set
-+# CONFIG_IO_DELAY_UDELAY is not set
-+# CONFIG_IO_DELAY_NONE is not set
-+CONFIG_DEFAULT_IO_DELAY_TYPE=0
-+CONFIG_DEBUG_BOOT_PARAMS=y
-+# CONFIG_CPA_DEBUG is not set
-+CONFIG_OPTIMIZE_INLINING=y
-+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
-+# CONFIG_DEBUG_NMI_SELFTEST is not set
-+
-+#
-+# Security options
-+#
-+CONFIG_KEYS=y
-+# CONFIG_ENCRYPTED_KEYS is not set
-+CONFIG_KEYS_DEBUG_PROC_KEYS=y
-+# CONFIG_SECURITY_DMESG_RESTRICT is not set
-+CONFIG_SECURITY=y
-+# CONFIG_SECURITYFS is not set
-+CONFIG_SECURITY_NETWORK=y
-+# CONFIG_SECURITY_NETWORK_XFRM is not set
-+# CONFIG_SECURITY_PATH is not set
-+# CONFIG_SECURITY_SMACK is not set
-+# CONFIG_SECURITY_TOMOYO is not set
-+# CONFIG_SECURITY_APPARMOR is not set
-+# CONFIG_SECURITY_YAMA is not set
-+# CONFIG_IMA is not set
-+# CONFIG_EVM is not set
-+CONFIG_DEFAULT_SECURITY_DAC=y
-+CONFIG_DEFAULT_SECURITY=""
-+CONFIG_CRYPTO=y
-+
-+#
-+# Crypto core or helper
-+#
-+CONFIG_CRYPTO_ALGAPI=y
-+CONFIG_CRYPTO_ALGAPI2=y
-+CONFIG_CRYPTO_AEAD2=y
-+CONFIG_CRYPTO_BLKCIPHER=m
-+CONFIG_CRYPTO_BLKCIPHER2=y
-+CONFIG_CRYPTO_HASH=y
-+CONFIG_CRYPTO_HASH2=y
-+CONFIG_CRYPTO_RNG=m
-+CONFIG_CRYPTO_RNG2=y
-+CONFIG_CRYPTO_PCOMP2=y
-+CONFIG_CRYPTO_MANAGER=m
-+CONFIG_CRYPTO_MANAGER2=y
-+# CONFIG_CRYPTO_USER is not set
-+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
-+# CONFIG_CRYPTO_GF128MUL is not set
-+# CONFIG_CRYPTO_NULL is not set
-+CONFIG_CRYPTO_WORKQUEUE=y
-+# CONFIG_CRYPTO_CRYPTD is not set
-+# CONFIG_CRYPTO_AUTHENC is not set
-+# CONFIG_CRYPTO_TEST is not set
-+
-+#
-+# Authenticated Encryption with Associated Data
-+#
-+# CONFIG_CRYPTO_CCM is not set
-+# CONFIG_CRYPTO_GCM is not set
-+# CONFIG_CRYPTO_SEQIV is not set
-+
-+#
-+# Block modes
-+#
-+# CONFIG_CRYPTO_CBC is not set
-+# CONFIG_CRYPTO_CTR is not set
-+# CONFIG_CRYPTO_CTS is not set
-+CONFIG_CRYPTO_ECB=m
-+# CONFIG_CRYPTO_LRW is not set
-+# CONFIG_CRYPTO_PCBC is not set
-+# CONFIG_CRYPTO_XTS is not set
-+
-+#
-+# Hash modes
-+#
-+# CONFIG_CRYPTO_HMAC is not set
-+# CONFIG_CRYPTO_XCBC is not set
-+# CONFIG_CRYPTO_VMAC is not set
-+
-+#
-+# Digest
-+#
-+CONFIG_CRYPTO_CRC32C=y
-+# CONFIG_CRYPTO_CRC32C_INTEL is not set
-+# CONFIG_CRYPTO_GHASH is not set
-+# CONFIG_CRYPTO_MD4 is not set
-+# CONFIG_CRYPTO_MD5 is not set
-+# CONFIG_CRYPTO_MICHAEL_MIC is not set
-+# CONFIG_CRYPTO_RMD128 is not set
-+# CONFIG_CRYPTO_RMD160 is not set
-+# CONFIG_CRYPTO_RMD256 is not set
-+# CONFIG_CRYPTO_RMD320 is not set
-+# CONFIG_CRYPTO_SHA1 is not set
-+CONFIG_CRYPTO_SHA256=m
-+# CONFIG_CRYPTO_SHA512 is not set
-+# CONFIG_CRYPTO_TGR192 is not set
-+# CONFIG_CRYPTO_WP512 is not set
-+
-+#
-+# Ciphers
-+#
-+CONFIG_CRYPTO_AES=y
-+# CONFIG_CRYPTO_AES_586 is not set
-+# CONFIG_CRYPTO_AES_NI_INTEL is not set
-+# CONFIG_CRYPTO_ANUBIS is not set
-+CONFIG_CRYPTO_ARC4=m
-+# CONFIG_CRYPTO_BLOWFISH is not set
-+# CONFIG_CRYPTO_CAMELLIA is not set
-+# CONFIG_CRYPTO_CAST5 is not set
-+# CONFIG_CRYPTO_CAST6 is not set
-+# CONFIG_CRYPTO_DES is not set
-+# CONFIG_CRYPTO_FCRYPT is not set
-+# CONFIG_CRYPTO_KHAZAD is not set
-+# CONFIG_CRYPTO_SALSA20 is not set
-+# CONFIG_CRYPTO_SALSA20_586 is not set
-+# CONFIG_CRYPTO_SEED is not set
-+# CONFIG_CRYPTO_SERPENT is not set
-+# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
-+# CONFIG_CRYPTO_TEA is not set
-+# CONFIG_CRYPTO_TWOFISH is not set
-+# CONFIG_CRYPTO_TWOFISH_586 is not set
-+
-+#
-+# Compression
-+#
-+# CONFIG_CRYPTO_DEFLATE is not set
-+# CONFIG_CRYPTO_ZLIB is not set
-+# CONFIG_CRYPTO_LZO is not set
-+
-+#
-+# Random Number Generation
-+#
-+CONFIG_CRYPTO_ANSI_CPRNG=m
-+# CONFIG_CRYPTO_USER_API_HASH is not set
-+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
-+CONFIG_CRYPTO_HW=y
-+# CONFIG_CRYPTO_DEV_PADLOCK is not set
-+# CONFIG_CRYPTO_DEV_GEODE is not set
-+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
-+CONFIG_HAVE_KVM=y
-+# CONFIG_VIRTUALIZATION is not set
-+# CONFIG_BINARY_PRINTF is not set
-+
-+#
-+# Library routines
-+#
-+CONFIG_BITREVERSE=y
-+CONFIG_GENERIC_STRNCPY_FROM_USER=y
-+CONFIG_GENERIC_STRNLEN_USER=y
-+CONFIG_GENERIC_FIND_FIRST_BIT=y
-+CONFIG_GENERIC_PCI_IOMAP=y
-+CONFIG_GENERIC_IOMAP=y
-+CONFIG_GENERIC_IO=y
-+CONFIG_PERCPU_RWSEM=y
-+CONFIG_CRC_CCITT=m
-+CONFIG_CRC16=y
-+CONFIG_CRC_T10DIF=y
-+# CONFIG_CRC_ITU_T is not set
-+CONFIG_CRC32=y
-+# CONFIG_CRC32_SELFTEST is not set
-+CONFIG_CRC32_SLICEBY8=y
-+# CONFIG_CRC32_SLICEBY4 is not set
-+# CONFIG_CRC32_SARWATE is not set
-+# CONFIG_CRC32_BIT is not set
-+# CONFIG_CRC7 is not set
-+# CONFIG_LIBCRC32C is not set
-+# CONFIG_CRC8 is not set
-+CONFIG_ZLIB_INFLATE=y
-+CONFIG_ZLIB_DEFLATE=m
-+# CONFIG_XZ_DEC is not set
-+# CONFIG_XZ_DEC_BCJ is not set
-+CONFIG_DECOMPRESS_GZIP=y
-+CONFIG_DECOMPRESS_BZIP2=y
-+CONFIG_DECOMPRESS_LZMA=y
-+CONFIG_HAS_IOMEM=y
-+CONFIG_HAS_IOPORT=y
-+CONFIG_HAS_DMA=y
-+CONFIG_DQL=y
-+CONFIG_NLATTR=y
-+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
-+CONFIG_AVERAGE=y
-+# CONFIG_CORDIC is not set
-+# CONFIG_DDR is not set
-diff --git a/net/ieee802154/wpan-class.c b/net/ieee802154/wpan-class.c
-index 1627ef2..13571ea 100644
---- a/net/ieee802154/wpan-class.c
-+++ b/net/ieee802154/wpan-class.c
-@@ -91,7 +91,7 @@ static struct class wpan_phy_class = {
- static DEFINE_MUTEX(wpan_phy_mutex);
- static int wpan_phy_idx;
-
--static int wpan_phy_match(struct device *dev, void *data)
-+static int wpan_phy_match(struct device *dev, const void *data)
- {
- return !strcmp(dev_name(dev), (const char *)data);
- }
-@@ -103,8 +103,7 @@ struct wpan_phy *wpan_phy_find(const char *str)
- if (WARN_ON(!str))
- return NULL;
-
-- dev = class_find_device(&wpan_phy_class, NULL,
-- (void *)str, wpan_phy_match);
-+ dev = class_find_device(&wpan_phy_class, NULL, str, wpan_phy_match);
- if (!dev)
- return NULL;
-
-diff --git a/net/nfc/core.c b/net/nfc/core.c
-index aa64ea4..0f4a6de 100644
---- a/net/nfc/core.c
-+++ b/net/nfc/core.c
-@@ -734,10 +734,10 @@ struct class nfc_class = {
- };
- EXPORT_SYMBOL(nfc_class);
-
--static int match_idx(struct device *d, void *data)
-+static int match_idx(struct device *d, const void *data)
- {
- struct nfc_dev *dev = to_nfc_dev(d);
-- unsigned int *idx = data;
-+ const unsigned int *idx = data;
-
- return dev->idx == *idx;
- }
diff --git a/recipes-kernel/linux/files/clanton.cfg b/recipes-kernel/linux/files/quark.cfg
index 721ee1c..30b2e33 100644
--- a/recipes-kernel/linux/files/clanton.cfg
+++ b/recipes-kernel/linux/files/quark.cfg
@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
-# Linux/x86 3.8.7 Kernel Configuration
+# Linux/i386 3.8.7 Kernel Configuration
#
# CONFIG_64BIT is not set
CONFIG_X86_32=y
@@ -137,8 +137,11 @@ CONFIG_FAIR_GROUP_SCHED=y
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
CONFIG_PID_NS=y
CONFIG_NET_NS=y
+CONFIG_UIDGID_CONVERTED=y
+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
# CONFIG_SCHED_AUTOGROUP is not set
# CONFIG_SYSFS_DEPRECATED is not set
CONFIG_RELAY=y
@@ -643,7 +646,7 @@ CONFIG_LLC=m
# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
-CONFIG_DNS_RESOLVER=m
+# CONFIG_DNS_RESOLVER is not set
# CONFIG_BATMAN_ADV is not set
# CONFIG_OPENVSWITCH is not set
# CONFIG_NETPRIO_CGROUP is not set
@@ -796,7 +799,7 @@ CONFIG_M25PXX_USE_FAST_READ=y
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_MTD_CLN_ROM is not set
+# CONFIG_MTD_MTD_QRK_ROM is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -1523,8 +1526,8 @@ CONFIG_MFD_CORE=y
# CONFIG_MFD_CS5535 is not set
# CONFIG_MFD_TIMBERDALE is not set
CONFIG_CY8C9540A=m
-CONFIG_INTEL_CLN_GIP=m
-CONFIG_INTEL_CLN_GIP_TEST=m
+CONFIG_INTEL_QRK_GIP=m
+CONFIG_INTEL_QRK_GIP_TEST=m
CONFIG_LPC_SCH=y
# CONFIG_LPC_ICH is not set
# CONFIG_MFD_RDC321X is not set
@@ -2482,10 +2485,10 @@ CONFIG_X86_PLATFORM_DEVICES=y
# CONFIG_TOPSTAR_LAPTOP is not set
# CONFIG_TOSHIBA_BT_RFKILL is not set
# CONFIG_ACPI_CMPC is not set
-CONFIG_INTEL_CLN_ESRAM=y
-CONFIG_INTEL_CLN_ECC_REFRESH_PERIOD=24
-CONFIG_INTEL_CLN_THERMAL=y
-CONFIG_INTEL_CLN_AUDIO_CTRL=m
+CONFIG_INTEL_QRK_ESRAM=y
+CONFIG_INTEL_QRK_ECC_REFRESH_PERIOD=24
+CONFIG_INTEL_QRK_THERMAL=y
+CONFIG_INTEL_QRK_AUDIO_CTRL=m
# CONFIG_INTEL_IPS is not set
# CONFIG_IBM_RTL is not set
# CONFIG_XO15_EBOOK is not set
@@ -2521,7 +2524,7 @@ CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
#
# Accelerometers
#
-CONFIG_IIO_LIS331DLH_INTEL_CLN=m
+CONFIG_IIO_LIS331DLH_INTEL_QRK=m
#
# Analog to digital converters
@@ -2686,22 +2689,8 @@ CONFIG_HUGETLB_PAGE=y
# CONFIG_CONFIGFS_FS is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V2=m
-CONFIG_NFS_V3=m
-# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=m
-# CONFIG_NFS_SWAP is not set
-# CONFIG_NFS_V4_1 is not set
-# CONFIG_NFS_USE_LEGACY_DNS is not set
-CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-# CONFIG_SUNRPC_DEBUG is not set
# CONFIG_CEPH_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
diff --git a/recipes-kernel/linux/linux-yocto-clanton_3.8.bb b/recipes-kernel/linux/linux-yocto-clanton_3.8.bb
index 98cf739..9bb8f69 100644
--- a/recipes-kernel/linux/linux-yocto-clanton_3.8.bb
+++ b/recipes-kernel/linux/linux-yocto-clanton_3.8.bb
@@ -48,8 +48,7 @@ require recipes-kernel/linux/linux-yocto.inc
SRC_URI = "git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git;branch=linux-3.8.y"
-SRC_URI += "file://clanton.patch"
-SRC_URI += "file://clanton.cfg"
+SRC_URI += "file://quark.cfg"
SRC_URI += "file://clanton-standard.scc"
SRC_URI += "file://0001-libtraceevent-Remove-hard-coded-include-to-usr-local.patch"
@@ -59,6 +58,7 @@ LINUX_VERSION_EXTENSION ?= "-clanton"
# Override SRCREV to point to a different commit in a bbappend file to
# build a different release of the Linux kernel.
SRCREV = "531ec28f9f26f78797124b9efcf2138b89794a1e"
+SRCREV_machine_clanton = "531ec28f9f26f78797124b9efcf2138b89794a1e"
PR = "r0"
PV = "${LINUX_VERSION}"
@@ -68,3 +68,27 @@ PV = "${LINUX_VERSION}"
COMPATIBLE_MACHINE = "clanton"
RDEPENDS_kernel-base=""
+
+SRC_URI += "file://0001-tty-don-t-deadlock-while-flushing-workqueue-quark.patch"
+SRC_URI += "file://0002-driver-core-constify-data-for-class_find_devic-quark.patch"
+SRC_URI += "file://0003-TTY-mark-tty_get_device-call-with-the-proper-c-quark.patch"
+SRC_URI += "file://0004-pwm-Add-sysfs-interface-quark.patch"
+SRC_URI += "file://0005-drivers-pwm-sysfs.c-add-export.h-RTC-50404-quark.patch"
+SRC_URI += "file://0006-core-Quark-patch-quark.patch"
+SRC_URI += "file://0007-Quark-Platform-Code-quark.patch"
+SRC_URI += "file://0008-Quark-UART-quark.patch"
+SRC_URI += "file://0009-EFI-capsule-update-quark.patch"
+SRC_URI += "file://0010-Quark-SDIO-host-controller-quark.patch"
+SRC_URI += "file://0011-Quark-USB-host-quark.patch"
+SRC_URI += "file://0012-USB-gadget-serial-quark.patch"
+SRC_URI += "file://0013-Quark-stmmac-Ethernet-quark.patch"
+SRC_URI += "file://0014-Quark-GPIO-2-2-quark.patch"
+SRC_URI += "file://0015-Quark-GPIO-1-2-quark.patch"
+SRC_URI += "file://0016-Quark-GIP-Cypress-I-O-expander-quark.patch"
+SRC_URI += "file://0017-Quark-I2C-quark.patch"
+SRC_URI += "file://0018-Quark-sensors-quark.patch"
+SRC_URI += "file://0019-Quark-SC-SPI-quark.patch"
+SRC_URI += "file://0020-Quark-IIO-quark.patch"
+SRC_URI += "file://0021-Quark-SPI-flash-quark.patch"
+SRC_URI += "file://0001-libtraceevent-Remove-hard-coded-include-to-usr-local.patch"
+