diff options
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, ®, 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, ®, 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, ®val, 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, ®val); ++ 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, ®val); ++ 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, ®, 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, ®, 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, ®val, 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" + |