]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
Merge tag 'intel-gpio-v5.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/andy...
authorLinus Walleij <linus.walleij@linaro.org>
Wed, 13 Nov 2019 22:03:23 +0000 (23:03 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Wed, 13 Nov 2019 22:03:23 +0000 (23:03 +0100)
intel-gpio for v5.5-1

* Prerequisite patch against GPIO library to register pin ranges in time.
* Second attempt to fix Intel Merrifield GPIO driver to utilize irqchip.

The following is an automated git shortlog grouped by driver:

gpiolib:
 -  Introduce ->add_pin_ranges() callback

merrifield:
 -  Pass irqchip when adding gpiochip
 -  Add GPIO <-> pin mapping ranges via callback

81 files changed:
Documentation/admin-guide/kernel-parameters.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/driver-api/device_link.rst
Documentation/driver-api/driver-model/devres.rst
Documentation/driver-api/driver-model/driver.rst
Documentation/filesystems/debugfs.txt
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/hvCall_inst.c
arch/powerpc/platforms/pseries/lpar.c
arch/sh/drivers/Makefile
arch/sh/drivers/platform_early.c [new file with mode: 0644]
arch/sh/include/asm/platform_early.h [new file with mode: 0644]
arch/sh/kernel/cpu/sh2/setup-sh7619.c
arch/sh/kernel/cpu/sh2a/setup-mxg.c
arch/sh/kernel/cpu/sh2a/setup-sh7201.c
arch/sh/kernel/cpu/sh2a/setup-sh7203.c
arch/sh/kernel/cpu/sh2a/setup-sh7206.c
arch/sh/kernel/cpu/sh2a/setup-sh7264.c
arch/sh/kernel/cpu/sh2a/setup-sh7269.c
arch/sh/kernel/cpu/sh3/setup-sh3.c
arch/sh/kernel/cpu/sh3/setup-sh7705.c
arch/sh/kernel/cpu/sh3/setup-sh770x.c
arch/sh/kernel/cpu/sh3/setup-sh7710.c
arch/sh/kernel/cpu/sh3/setup-sh7720.c
arch/sh/kernel/cpu/sh4/setup-sh4-202.c
arch/sh/kernel/cpu/sh4/setup-sh7750.c
arch/sh/kernel/cpu/sh4/setup-sh7760.c
arch/sh/kernel/cpu/sh4a/setup-sh7343.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7722.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/setup-sh7724.c
arch/sh/kernel/cpu/sh4a/setup-sh7734.c
arch/sh/kernel/cpu/sh4a/setup-sh7757.c
arch/sh/kernel/cpu/sh4a/setup-sh7763.c
arch/sh/kernel/cpu/sh4a/setup-sh7770.c
arch/sh/kernel/cpu/sh4a/setup-sh7780.c
arch/sh/kernel/cpu/sh4a/setup-sh7785.c
arch/sh/kernel/cpu/sh4a/setup-sh7786.c
arch/sh/kernel/cpu/sh4a/setup-shx3.c
arch/sh/kernel/cpu/sh5/setup-sh5.c
arch/sh/kernel/setup.c
arch/sh/kernel/time.c
drivers/base/core.c
drivers/base/firmware_loader/main.c
drivers/base/platform.c
drivers/base/soc.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/gpio/gpio-bd70528.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-mmio.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-xgs-iproc.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/bridge/ti-tfp410.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c
drivers/misc/sram.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc.c
drivers/net/caif/caif_serial.c
drivers/ntb/test/ntb_pingpong.c
drivers/of/platform.c
drivers/of/property.c
drivers/tty/serial/sh-sci.c
fs/debugfs/file.c
include/linux/debugfs.h
include/linux/device.h
include/linux/fwnode.h
include/linux/platform_device.h
include/linux/sys_soc.h
include/uapi/linux/gpio.h
lib/devres.c
net/mac80211/debugfs_sta.c

index d05d531b4ec9f3f4288845cc3e84296b009b1942..6d421694d98e9e2f528877949fc2ca1e40802650 100644 (file)
@@ -127,6 +127,7 @@ parameter is applicable::
        NET     Appropriate network support is enabled.
        NUMA    NUMA support is enabled.
        NFS     Appropriate NFS support is enabled.
+       OF      Devicetree is enabled.
        OSS     OSS sound support is enabled.
        PV_OPS  A paravirtualized kernel is enabled.
        PARIDE  The ParIDE (parallel port IDE) subsystem is enabled.
index a84a83f8881e08bf0d0d598bb01814be0ec18647..dc727fa8c831da90b48363374cdfee05e559b2e5 100644 (file)
                        This can be set from sysctl after boot.
                        See Documentation/admin-guide/sysctl/vm.rst for details.
 
+       of_devlink      [OF, KNL] Create device links between consumer and
+                       supplier devices by scanning the devictree to infer the
+                       consumer/supplier relationships.  A consumer device
+                       will not be probed until all the supplier devices have
+                       probed successfully.
+
        ohci1394_dma=early      [HW] enable debugging via the ohci1394 driver.
                        See Documentation/debugging-via-ohci1394.txt for more
                        info.
index 1b5020ec6517b06ae01e0f57db976bc41ce81d5b..bc2d89af88ce2da221cfac37dee585dd4c11ca42 100644 (file)
@@ -281,7 +281,8 @@ State machine
   :c:func:`driver_bound()`.)
 
 * Before a consumer device is probed, presence of supplier drivers is
-  verified by checking that links to suppliers are in ``DL_STATE_AVAILABLE``
+  verified by checking the consumer device is not in the wait_for_suppliers
+  list and by checking that links to suppliers are in ``DL_STATE_AVAILABLE``
   state.  The state of the links is updated to ``DL_STATE_CONSUMER_PROBE``.
   (Call to :c:func:`device_links_check_suppliers()` from
   :c:func:`really_probe()`.)
index a100bef5495284d93ee487a7b2ad44985869497d..4ab193319d8c60bcea4ed41d29587ca32fc9fabe 100644 (file)
@@ -316,6 +316,10 @@ IOMAP
   devm_ioremap_nocache()
   devm_ioremap_wc()
   devm_ioremap_resource() : checks resource, requests memory region, ioremaps
+  devm_ioremap_resource_wc()
+  devm_platform_ioremap_resource() : calls devm_ioremap_resource() for platform device
+  devm_platform_ioremap_resource_wc()
+  devm_platform_ioremap_resource_byname()
   devm_iounmap()
   pcim_iomap()
   pcim_iomap_regions() : do request_region() and iomap() on multiple BARs
index 11d281506a0415219e945c49684b2977ea873d7e..baa6a85c82871b40f9aa43bd505efc89febedeb2 100644 (file)
@@ -169,6 +169,49 @@ A driver's probe() may return a negative errno value to indicate that
 the driver did not bind to this device, in which case it should have
 released all resources it allocated::
 
+       void (*sync_state)(struct device *dev);
+
+sync_state is called only once for a device. It's called when all the consumer
+devices of the device have successfully probed. The list of consumers of the
+device is obtained by looking at the device links connecting that device to its
+consumer devices.
+
+The first attempt to call sync_state() is made during late_initcall_sync() to
+give firmware and drivers time to link devices to each other. During the first
+attempt at calling sync_state(), if all the consumers of the device at that
+point in time have already probed successfully, sync_state() is called right
+away. If there are no consumers of the device during the first attempt, that
+too is considered as "all consumers of the device have probed" and sync_state()
+is called right away.
+
+If during the first attempt at calling sync_state() for a device, there are
+still consumers that haven't probed successfully, the sync_state() call is
+postponed and reattempted in the future only when one or more consumers of the
+device probe successfully. If during the reattempt, the driver core finds that
+there are one or more consumers of the device that haven't probed yet, then
+sync_state() call is postponed again.
+
+A typical use case for sync_state() is to have the kernel cleanly take over
+management of devices from the bootloader. For example, if a device is left on
+and at a particular hardware configuration by the bootloader, the device's
+driver might need to keep the device in the boot configuration until all the
+consumers of the device have probed. Once all the consumers of the device have
+probed, the device's driver can synchronize the hardware state of the device to
+match the aggregated software state requested by all the consumers. Hence the
+name sync_state().
+
+While obvious examples of resources that can benefit from sync_state() include
+resources such as regulator, sync_state() can also be useful for complex
+resources like IOMMUs. For example, IOMMUs with multiple consumers (devices
+whose addresses are remapped by the IOMMU) might need to keep their mappings
+fixed at (or additive to) the boot configuration until all its consumers have
+probed.
+
+While the typical use case for sync_state() is to have the kernel cleanly take
+over management of devices from the bootloader, the usage of sync_state() is
+not restricted to that. Use it whenever it makes sense to take an action after
+all the consumers of a device have probed.
+
        int     (*remove)       (struct device *dev);
 
 remove is called to unbind a driver from a device. This may be
index 9e27c843d00ea0602e391f760c05764066a544c0..dc497b96fa4ff54dc6b84cbf2951391a369473c0 100644 (file)
@@ -68,41 +68,49 @@ actually necessary; the debugfs code provides a number of helper functions
 for simple situations.  Files containing a single integer value can be
 created with any of:
 
-    struct dentry *debugfs_create_u8(const char *name, umode_t mode,
-                                    struct dentry *parent, u8 *value);
-    struct dentry *debugfs_create_u16(const char *name, umode_t mode,
-                                     struct dentry *parent, u16 *value);
+    void debugfs_create_u8(const char *name, umode_t mode,
+                          struct dentry *parent, u8 *value);
+    void debugfs_create_u16(const char *name, umode_t mode,
+                           struct dentry *parent, u16 *value);
     struct dentry *debugfs_create_u32(const char *name, umode_t mode,
                                      struct dentry *parent, u32 *value);
-    struct dentry *debugfs_create_u64(const char *name, umode_t mode,
-                                     struct dentry *parent, u64 *value);
+    void debugfs_create_u64(const char *name, umode_t mode,
+                           struct dentry *parent, u64 *value);
 
 These files support both reading and writing the given value; if a specific
 file should not be written to, simply set the mode bits accordingly.  The
 values in these files are in decimal; if hexadecimal is more appropriate,
 the following functions can be used instead:
 
-    struct dentry *debugfs_create_x8(const char *name, umode_t mode,
-                                    struct dentry *parent, u8 *value);
-    struct dentry *debugfs_create_x16(const char *name, umode_t mode,
-                                     struct dentry *parent, u16 *value);
-    struct dentry *debugfs_create_x32(const char *name, umode_t mode,
-                                     struct dentry *parent, u32 *value);
-    struct dentry *debugfs_create_x64(const char *name, umode_t mode,
-                                     struct dentry *parent, u64 *value);
+    void debugfs_create_x8(const char *name, umode_t mode,
+                          struct dentry *parent, u8 *value);
+    void debugfs_create_x16(const char *name, umode_t mode,
+                           struct dentry *parent, u16 *value);
+    void debugfs_create_x32(const char *name, umode_t mode,
+                           struct dentry *parent, u32 *value);
+    void debugfs_create_x64(const char *name, umode_t mode,
+                           struct dentry *parent, u64 *value);
 
 These functions are useful as long as the developer knows the size of the
 value to be exported.  Some types can have different widths on different
-architectures, though, complicating the situation somewhat.  There is a
-function meant to help out in one special case:
+architectures, though, complicating the situation somewhat.  There are
+functions meant to help out in such special cases:
 
-    struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
-                                        struct dentry *parent, 
-                                        size_t *value);
+    void debugfs_create_size_t(const char *name, umode_t mode,
+                              struct dentry *parent, size_t *value);
 
 As might be expected, this function will create a debugfs file to represent
 a variable of type size_t.
 
+Similarly, there are helpers for variables of type unsigned long, in decimal
+and hexadecimal:
+
+    struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
+                                       struct dentry *parent,
+                                       unsigned long *value);
+    void debugfs_create_xul(const char *name, umode_t mode,
+                           struct dentry *parent, unsigned long *value);
+
 Boolean values can be placed in debugfs with:
 
     struct dentry *debugfs_create_bool(const char *name, umode_t mode,
@@ -114,8 +122,8 @@ lower-case values, or 1 or 0.  Any other input will be silently ignored.
 
 Also, atomic_t values can be placed in debugfs with:
 
-    struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
-                               struct dentry *parent, atomic_t *value)
+    void debugfs_create_atomic_t(const char *name, umode_t mode,
+                                struct dentry *parent, atomic_t *value)
 
 A read of this file will get atomic_t values, and a write of this file
 will set atomic_t values.
index 2b87480f2837ae3241cd2acacd50f31ce5461bcb..eab8aa293743b421fba23cb266a2843d7e489033 100644 (file)
@@ -19,7 +19,6 @@
 
 struct dtl {
        struct dtl_entry        *buf;
-       struct dentry           *file;
        int                     cpu;
        int                     buf_entries;
        u64                     last_idx;
@@ -320,46 +319,28 @@ static const struct file_operations dtl_fops = {
 
 static struct dentry *dtl_dir;
 
-static int dtl_setup_file(struct dtl *dtl)
+static void dtl_setup_file(struct dtl *dtl)
 {
        char name[10];
 
        sprintf(name, "cpu-%d", dtl->cpu);
 
-       dtl->file = debugfs_create_file(name, 0400, dtl_dir, dtl, &dtl_fops);
-       if (!dtl->file)
-               return -ENOMEM;
-
-       return 0;
+       debugfs_create_file(name, 0400, dtl_dir, dtl, &dtl_fops);
 }
 
 static int dtl_init(void)
 {
-       struct dentry *event_mask_file, *buf_entries_file;
-       int rc, i;
+       int i;
 
        if (!firmware_has_feature(FW_FEATURE_SPLPAR))
                return -ENODEV;
 
        /* set up common debugfs structure */
 
-       rc = -ENOMEM;
        dtl_dir = debugfs_create_dir("dtl", powerpc_debugfs_root);
-       if (!dtl_dir) {
-               printk(KERN_WARNING "%s: can't create dtl root dir\n",
-                               __func__);
-               goto err;
-       }
 
-       event_mask_file = debugfs_create_x8("dtl_event_mask", 0600,
-                               dtl_dir, &dtl_event_mask);
-       buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400,
-                               dtl_dir, &dtl_buf_entries);
-
-       if (!event_mask_file || !buf_entries_file) {
-               printk(KERN_WARNING "%s: can't create dtl files\n", __func__);
-               goto err_remove_dir;
-       }
+       debugfs_create_x8("dtl_event_mask", 0600, dtl_dir, &dtl_event_mask);
+       debugfs_create_u32("dtl_buf_entries", 0400, dtl_dir, &dtl_buf_entries);
 
        /* set up the per-cpu log structures */
        for_each_possible_cpu(i) {
@@ -367,16 +348,9 @@ static int dtl_init(void)
                spin_lock_init(&dtl->lock);
                dtl->cpu = i;
 
-               rc = dtl_setup_file(dtl);
-               if (rc)
-                       goto err_remove_dir;
+               dtl_setup_file(dtl);
        }
 
        return 0;
-
-err_remove_dir:
-       debugfs_remove_recursive(dtl_dir);
-err:
-       return rc;
 }
 machine_arch_initcall(pseries, dtl_init);
index bcc1b67417a84b066d65ac9e37a851acf893e10d..c40c62ec432e277f4cfebcf979ce2d4fc9881ac4 100644 (file)
@@ -129,7 +129,6 @@ static void probe_hcall_exit(void *ignored, unsigned long opcode, long retval,
 static int __init hcall_inst_init(void)
 {
        struct dentry *hcall_root;
-       struct dentry *hcall_file;
        char cpu_name_buf[CPU_NAME_BUF_SIZE];
        int cpu;
 
@@ -145,17 +144,12 @@ static int __init hcall_inst_init(void)
        }
 
        hcall_root = debugfs_create_dir(HCALL_ROOT_DIR, NULL);
-       if (!hcall_root)
-               return -ENOMEM;
 
        for_each_possible_cpu(cpu) {
                snprintf(cpu_name_buf, CPU_NAME_BUF_SIZE, "cpu%d", cpu);
-               hcall_file = debugfs_create_file(cpu_name_buf, 0444,
-                                                hcall_root,
-                                                per_cpu(hcall_stats, cpu),
-                                                &hcall_inst_seq_fops);
-               if (!hcall_file)
-                       return -ENOMEM;
+               debugfs_create_file(cpu_name_buf, 0444, hcall_root,
+                                   per_cpu(hcall_stats, cpu),
+                                   &hcall_inst_seq_fops);
        }
 
        return 0;
index f87a5c64e24dcf534de83255baf8d7bbd441433f..f9f57c55655ecf1f12d8f9f6d46953ce7d365d6b 100644 (file)
@@ -1998,24 +1998,11 @@ static int __init vpa_debugfs_init(void)
                return 0;
 
        vpa_dir = debugfs_create_dir("vpa", powerpc_debugfs_root);
-       if (!vpa_dir) {
-               pr_warn("%s: can't create vpa root dir\n", __func__);
-               return -ENOMEM;
-       }
 
        /* set up the per-cpu vpa file*/
        for_each_possible_cpu(i) {
-               struct dentry *d;
-
                sprintf(name, "cpu-%ld", i);
-
-               d = debugfs_create_file(name, 0400, vpa_dir, (void *)i,
-                                       &vpa_fops);
-               if (!d) {
-                       pr_warn("%s: can't create per-cpu vpa file\n",
-                                       __func__);
-                       return -ENOMEM;
-               }
+               debugfs_create_file(name, 0400, vpa_dir, (void *)i, &vpa_fops);
        }
 
        return 0;
index 3e93b434e6048edea4e27c3c2577ffeb30c22667..56b0acace6e7c81092ba615d24d60ba50b95f162 100644 (file)
@@ -3,7 +3,7 @@
 # Makefile for the Linux SuperH-specific device drivers.
 #
 
-obj-y          += dma/
+obj-y          += dma/ platform_early.o
 
 obj-$(CONFIG_PCI)              += pci/
 obj-$(CONFIG_SUPERHYWAY)       += superhyway/
diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c
new file mode 100644 (file)
index 0000000..f6d1484
--- /dev/null
@@ -0,0 +1,347 @@
+// SPDX--License-Identifier: GPL-2.0
+
+#include <asm/platform_early.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+
+static __initdata LIST_HEAD(sh_early_platform_driver_list);
+static __initdata LIST_HEAD(sh_early_platform_device_list);
+
+static const struct platform_device_id *
+platform_match_id(const struct platform_device_id *id,
+                 struct platform_device *pdev)
+{
+       while (id->name[0]) {
+               if (strcmp(pdev->name, id->name) == 0) {
+                       pdev->id_entry = id;
+                       return id;
+               }
+               id++;
+       }
+       return NULL;
+}
+
+static int platform_match(struct device *dev, struct device_driver *drv)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct platform_driver *pdrv = to_platform_driver(drv);
+
+       /* When driver_override is set, only bind to the matching driver */
+       if (pdev->driver_override)
+               return !strcmp(pdev->driver_override, drv->name);
+
+       /* Then try to match against the id table */
+       if (pdrv->id_table)
+               return platform_match_id(pdrv->id_table, pdev) != NULL;
+
+       /* fall-back to driver name match */
+       return (strcmp(pdev->name, drv->name) == 0);
+}
+
+#ifdef CONFIG_PM
+static void device_pm_init_common(struct device *dev)
+{
+       if (!dev->power.early_init) {
+               spin_lock_init(&dev->power.lock);
+               dev->power.qos = NULL;
+               dev->power.early_init = true;
+       }
+}
+
+static void pm_runtime_early_init(struct device *dev)
+{
+       dev->power.disable_depth = 1;
+       device_pm_init_common(dev);
+}
+#else
+static void pm_runtime_early_init(struct device *dev) {}
+#endif
+
+/**
+ * sh_early_platform_driver_register - register early platform driver
+ * @epdrv: sh_early_platform driver structure
+ * @buf: string passed from early_param()
+ *
+ * Helper function for sh_early_platform_init() / sh_early_platform_init_buffer()
+ */
+int __init sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
+                                         char *buf)
+{
+       char *tmp;
+       int n;
+
+       /* Simply add the driver to the end of the global list.
+        * Drivers will by default be put on the list in compiled-in order.
+        */
+       if (!epdrv->list.next) {
+               INIT_LIST_HEAD(&epdrv->list);
+               list_add_tail(&epdrv->list, &sh_early_platform_driver_list);
+       }
+
+       /* If the user has specified device then make sure the driver
+        * gets prioritized. The driver of the last device specified on
+        * command line will be put first on the list.
+        */
+       n = strlen(epdrv->pdrv->driver.name);
+       if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
+               list_move(&epdrv->list, &sh_early_platform_driver_list);
+
+               /* Allow passing parameters after device name */
+               if (buf[n] == '\0' || buf[n] == ',')
+                       epdrv->requested_id = -1;
+               else {
+                       epdrv->requested_id = simple_strtoul(&buf[n + 1],
+                                                            &tmp, 10);
+
+                       if (buf[n] != '.' || (tmp == &buf[n + 1])) {
+                               epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
+                               n = 0;
+                       } else
+                               n += strcspn(&buf[n + 1], ",") + 1;
+               }
+
+               if (buf[n] == ',')
+                       n++;
+
+               if (epdrv->bufsize) {
+                       memcpy(epdrv->buffer, &buf[n],
+                              min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
+                       epdrv->buffer[epdrv->bufsize - 1] = '\0';
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * sh_early_platform_add_devices - adds a number of early platform devices
+ * @devs: array of early platform devices to add
+ * @num: number of early platform devices in array
+ *
+ * Used by early architecture code to register early platform devices and
+ * their platform data.
+ */
+void __init sh_early_platform_add_devices(struct platform_device **devs, int num)
+{
+       struct device *dev;
+       int i;
+
+       /* simply add the devices to list */
+       for (i = 0; i < num; i++) {
+               dev = &devs[i]->dev;
+
+               if (!dev->devres_head.next) {
+                       pm_runtime_early_init(dev);
+                       INIT_LIST_HEAD(&dev->devres_head);
+                       list_add_tail(&dev->devres_head,
+                                     &sh_early_platform_device_list);
+               }
+       }
+}
+
+/**
+ * sh_early_platform_driver_register_all - register early platform drivers
+ * @class_str: string to identify early platform driver class
+ *
+ * Used by architecture code to register all early platform drivers
+ * for a certain class. If omitted then only early platform drivers
+ * with matching kernel command line class parameters will be registered.
+ */
+void __init sh_early_platform_driver_register_all(char *class_str)
+{
+       /* The "class_str" parameter may or may not be present on the kernel
+        * command line. If it is present then there may be more than one
+        * matching parameter.
+        *
+        * Since we register our early platform drivers using early_param()
+        * we need to make sure that they also get registered in the case
+        * when the parameter is missing from the kernel command line.
+        *
+        * We use parse_early_options() to make sure the early_param() gets
+        * called at least once. The early_param() may be called more than
+        * once since the name of the preferred device may be specified on
+        * the kernel command line. sh_early_platform_driver_register() handles
+        * this case for us.
+        */
+       parse_early_options(class_str);
+}
+
+/**
+ * sh_early_platform_match - find early platform device matching driver
+ * @epdrv: early platform driver structure
+ * @id: id to match against
+ */
+static struct platform_device * __init
+sh_early_platform_match(struct sh_early_platform_driver *epdrv, int id)
+{
+       struct platform_device *pd;
+
+       list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
+               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+                       if (pd->id == id)
+                               return pd;
+
+       return NULL;
+}
+
+/**
+ * sh_early_platform_left - check if early platform driver has matching devices
+ * @epdrv: early platform driver structure
+ * @id: return true if id or above exists
+ */
+static int __init sh_early_platform_left(struct sh_early_platform_driver *epdrv,
+                                      int id)
+{
+       struct platform_device *pd;
+
+       list_for_each_entry(pd, &sh_early_platform_device_list, dev.devres_head)
+               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
+                       if (pd->id >= id)
+                               return 1;
+
+       return 0;
+}
+
+/**
+ * sh_early_platform_driver_probe_id - probe drivers matching class_str and id
+ * @class_str: string to identify early platform driver class
+ * @id: id to match against
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ */
+static int __init sh_early_platform_driver_probe_id(char *class_str,
+                                                int id,
+                                                int nr_probe)
+{
+       struct sh_early_platform_driver *epdrv;
+       struct platform_device *match;
+       int match_id;
+       int n = 0;
+       int left = 0;
+
+       list_for_each_entry(epdrv, &sh_early_platform_driver_list, list) {
+               /* only use drivers matching our class_str */
+               if (strcmp(class_str, epdrv->class_str))
+                       continue;
+
+               if (id == -2) {
+                       match_id = epdrv->requested_id;
+                       left = 1;
+
+               } else {
+                       match_id = id;
+                       left += sh_early_platform_left(epdrv, id);
+
+                       /* skip requested id */
+                       switch (epdrv->requested_id) {
+                       case EARLY_PLATFORM_ID_ERROR:
+                       case EARLY_PLATFORM_ID_UNSET:
+                               break;
+                       default:
+                               if (epdrv->requested_id == id)
+                                       match_id = EARLY_PLATFORM_ID_UNSET;
+                       }
+               }
+
+               switch (match_id) {
+               case EARLY_PLATFORM_ID_ERROR:
+                       pr_warn("%s: unable to parse %s parameter\n",
+                               class_str, epdrv->pdrv->driver.name);
+                       /* fall-through */
+               case EARLY_PLATFORM_ID_UNSET:
+                       match = NULL;
+                       break;
+               default:
+                       match = sh_early_platform_match(epdrv, match_id);
+               }
+
+               if (match) {
+                       /*
+                        * Set up a sensible init_name to enable
+                        * dev_name() and others to be used before the
+                        * rest of the driver core is initialized.
+                        */
+                       if (!match->dev.init_name && slab_is_available()) {
+                               if (match->id != -1)
+                                       match->dev.init_name =
+                                               kasprintf(GFP_KERNEL, "%s.%d",
+                                                         match->name,
+                                                         match->id);
+                               else
+                                       match->dev.init_name =
+                                               kasprintf(GFP_KERNEL, "%s",
+                                                         match->name);
+
+                               if (!match->dev.init_name)
+                                       return -ENOMEM;
+                       }
+
+                       if (epdrv->pdrv->probe(match))
+                               pr_warn("%s: unable to probe %s early.\n",
+                                       class_str, match->name);
+                       else
+                               n++;
+               }
+
+               if (n >= nr_probe)
+                       break;
+       }
+
+       if (left)
+               return n;
+       else
+               return -ENODEV;
+}
+
+/**
+ * sh_early_platform_driver_probe - probe a class of registered drivers
+ * @class_str: string to identify early platform driver class
+ * @nr_probe: number of platform devices to successfully probe before exiting
+ * @user_only: only probe user specified early platform devices
+ *
+ * Used by architecture code to probe registered early platform drivers
+ * within a certain class. For probe to happen a registered early platform
+ * device matching a registered early platform driver is needed.
+ */
+int __init sh_early_platform_driver_probe(char *class_str,
+                                      int nr_probe,
+                                      int user_only)
+{
+       int k, n, i;
+
+       n = 0;
+       for (i = -2; n < nr_probe; i++) {
+               k = sh_early_platform_driver_probe_id(class_str, i, nr_probe - n);
+
+               if (k < 0)
+                       break;
+
+               n += k;
+
+               if (user_only)
+                       break;
+       }
+
+       return n;
+}
+
+/**
+ * sh_early_platform_cleanup - clean up early platform code
+ */
+static int __init sh_early_platform_cleanup(void)
+{
+       struct platform_device *pd, *pd2;
+
+       /* clean up the devres list used to chain devices */
+       list_for_each_entry_safe(pd, pd2, &sh_early_platform_device_list,
+                                dev.devres_head) {
+               list_del(&pd->dev.devres_head);
+               memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
+       }
+
+       return 0;
+}
+/*
+ * This must happen once after all early devices are probed but before probing
+ * real platform devices.
+ */
+subsys_initcall(sh_early_platform_cleanup);
diff --git a/arch/sh/include/asm/platform_early.h b/arch/sh/include/asm/platform_early.h
new file mode 100644 (file)
index 0000000..fc80213
--- /dev/null
@@ -0,0 +1,61 @@
+/* SPDX--License-Identifier: GPL-2.0 */
+
+#ifndef __PLATFORM_EARLY__
+#define __PLATFORM_EARLY__
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+struct sh_early_platform_driver {
+       const char *class_str;
+       struct platform_driver *pdrv;
+       struct list_head list;
+       int requested_id;
+       char *buffer;
+       int bufsize;
+};
+
+#define EARLY_PLATFORM_ID_UNSET -2
+#define EARLY_PLATFORM_ID_ERROR -3
+
+extern int sh_early_platform_driver_register(struct sh_early_platform_driver *epdrv,
+                                         char *buf);
+extern void sh_early_platform_add_devices(struct platform_device **devs, int num);
+
+static inline int is_sh_early_platform_device(struct platform_device *pdev)
+{
+       return !pdev->dev.driver;
+}
+
+extern void sh_early_platform_driver_register_all(char *class_str);
+extern int sh_early_platform_driver_probe(char *class_str,
+                                      int nr_probe, int user_only);
+
+#define sh_early_platform_init(class_string, platdrv)          \
+       sh_early_platform_init_buffer(class_string, platdrv, NULL, 0)
+
+#ifndef MODULE
+#define sh_early_platform_init_buffer(class_string, platdrv, buf, bufsiz)      \
+static __initdata struct sh_early_platform_driver early_driver = {             \
+       .class_str = class_string,                                      \
+       .buffer = buf,                                                  \
+       .bufsize = bufsiz,                                              \
+       .pdrv = platdrv,                                                \
+       .requested_id = EARLY_PLATFORM_ID_UNSET,                        \
+};                                                                     \
+static int __init sh_early_platform_driver_setup_func(char *buffer)    \
+{                                                                      \
+       return sh_early_platform_driver_register(&early_driver, buffer);        \
+}                                                                      \
+early_param(class_string, sh_early_platform_driver_setup_func)
+#else /* MODULE */
+#define sh_early_platform_init_buffer(class_string, platdrv, buf, bufsiz)      \
+static inline char *sh_early_platform_driver_setup_func(void)          \
+{                                                                      \
+       return bufsiz ? buf : NULL;                                     \
+}
+#endif /* MODULE */
+
+#endif /* __PLATFORM_EARLY__ */
index f5b6841ef7e1cd3783918e216b3c4b7471024157..b1c877b6a4207fefe73b02516fd87d03d7664c5e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sh_eth.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -199,6 +200,6 @@ void __init plat_early_device_setup(void)
        /* enable CMT clock */
        __raw_writeb(__raw_readb(STBCR3) & ~0x10, STBCR3);
 
-       early_platform_add_devices(sh7619_early_devices,
+       sh_early_platform_add_devices(sh7619_early_devices,
                                   ARRAY_SIZE(sh7619_early_devices));
 }
index 52350ad0b0a26a23e7158485bc6b63f0f6d93da6..cefa07924c16dbedf2737c06b641b6af0a22b43e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/serial.h>
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -169,6 +170,6 @@ static struct platform_device *mxg_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(mxg_early_devices,
+       sh_early_platform_add_devices(mxg_early_devices,
                                   ARRAY_SIZE(mxg_early_devices));
 }
index b51ed761ae087977e4bb4d3721636d830f67542f..28f1bebf340565db791824a7f0ae4d748f6e8d06 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -412,6 +413,6 @@ void __init plat_early_device_setup(void)
        /* enable MTU2 clock */
        __raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
 
-       early_platform_add_devices(sh7201_early_devices,
+       sh_early_platform_add_devices(sh7201_early_devices,
                                   ARRAY_SIZE(sh7201_early_devices));
 }
index 89b3e49fc2503673e5d5cf81ca82c4c6a1a9dcd2..4839f3aaeb4c21542dd1aa5beae7c0e444d7da6d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -349,6 +350,6 @@ void __init plat_early_device_setup(void)
        /* enable MTU2 clock */
        __raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
 
-       early_platform_add_devices(sh7203_early_devices,
+       sh_early_platform_add_devices(sh7203_early_devices,
                                   ARRAY_SIZE(sh7203_early_devices));
 }
index 36ff3a3139dabe1e98be6d60e32b0e56a1623d14..68add5af4cc56e3f5d1bfcebf14f660226fbe121 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/serial_sci.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -285,6 +286,6 @@ void __init plat_early_device_setup(void)
        /* enable MTU2 clock */
        __raw_writeb(__raw_readb(STBCR3) & ~0x20, STBCR3);
 
-       early_platform_add_devices(sh7206_early_devices,
+       sh_early_platform_add_devices(sh7206_early_devices,
                                   ARRAY_SIZE(sh7206_early_devices));
 }
index d199618d877c070b2a4176d32027ea96a12f330a..8a1cb613dd2e0478517c07e164f9431cefd16cce 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -546,6 +547,6 @@ static struct platform_device *sh7264_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7264_early_devices,
+       sh_early_platform_add_devices(sh7264_early_devices,
                                   ARRAY_SIZE(sh7264_early_devices));
 }
index 9095c960b4558d90c9037c1a5849412d531c9519..8b1ef3028320c75b67aff32bc96ae9553b23c2ae 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -562,6 +563,6 @@ static struct platform_device *sh7269_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7269_early_devices,
+       sh_early_platform_add_devices(sh7269_early_devices,
                                   ARRAY_SIZE(sh7269_early_devices));
 }
index 8058c01cf09dfd187d8b29ed48eb241cd6739836..cf2a3f09fee44348a09795239af82707757792f7 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 /* All SH3 devices are equipped with IRQ0->5 (except sh7708) */
 
index e19d1ce7b6ad1f09730f0a676b55c9c8c6e76ba6..0544134b3f20c631514377700ef48bda2c7117b4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sh_intc.h>
 #include <asm/rtc.h>
 #include <cpu/serial.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -178,7 +179,7 @@ static struct platform_device *sh7705_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7705_early_devices,
+       sh_early_platform_add_devices(sh7705_early_devices,
                                   ARRAY_SIZE(sh7705_early_devices));
 }
 
index 5c5144bee6bcc7ced870ccd785042b7c534eb224..4947f57748bc123208183eb778e9366cbaf70c60 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <cpu/serial.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -230,7 +231,7 @@ static struct platform_device *sh770x_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh770x_early_devices,
+       sh_early_platform_add_devices(sh770x_early_devices,
                                   ARRAY_SIZE(sh770x_early_devices));
 }
 
index 4776e2495738fde54720a9cbd5508672f727f7fa..3819107615794b085031d7e4bf93218c3a400fc2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <asm/rtc.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -177,7 +178,7 @@ static struct platform_device *sh7710_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7710_early_devices,
+       sh_early_platform_add_devices(sh7710_early_devices,
                                   ARRAY_SIZE(sh7710_early_devices));
 }
 
index 1d4c34e7b7db98ced3eafe368c3ff87dc1689ede..425d067dae9bafc327367c9bf20c8c308ec1e067 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/sh_intc.h>
 #include <linux/usb/ohci_pdriver.h>
 #include <asm/rtc.h>
+#include <asm/platform_early.h>
 #include <cpu/serial.h>
 
 static struct resource rtc_resources[] = {
@@ -211,7 +212,7 @@ static struct platform_device *sh7720_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7720_early_devices,
+       sh_early_platform_add_devices(sh7720_early_devices,
                                   ARRAY_SIZE(sh7720_early_devices));
 }
 
index a40ef35d101a9cb232ef69990aa1a1a329371e3b..e6737f3d0df25267e1c8daa3e63af39c85831ac0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE,
@@ -76,7 +77,7 @@ static struct platform_device *sh4202_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh4202_early_devices,
+       sh_early_platform_add_devices(sh4202_early_devices,
                                   ARRAY_SIZE(sh4202_early_devices));
 }
 
index b37bda66a532e8ddff486941114793db29bb62fa..19c8f1d69071c37ed036939c1b2c36a62631d496 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <generated/machtypes.h>
+#include <asm/platform_early.h>
 
 static struct resource rtc_resources[] = {
        [0] = {
@@ -161,15 +162,15 @@ void __init plat_early_device_setup(void)
        if (mach_is_rts7751r2d()) {
                scif_platform_data.scscr |= SCSCR_CKE1;
                dev[0] = &scif_device;
-               early_platform_add_devices(dev, 1);
+               sh_early_platform_add_devices(dev, 1);
        } else {
                dev[0] = &sci_device;
-               early_platform_add_devices(dev, 1);
+               sh_early_platform_add_devices(dev, 1);
                dev[0] = &scif_device;
-               early_platform_add_devices(dev, 1);
+               sh_early_platform_add_devices(dev, 1);
        }
 
-       early_platform_add_devices(sh7750_early_devices,
+       sh_early_platform_add_devices(sh7750_early_devices,
                                   ARRAY_SIZE(sh7750_early_devices));
 }
 
index 86845da859979da93e64c6e3da51b43f91fd7390..14212f5d803cd44a56a73f4af060bb9610a28c0d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sh_intc.h>
 #include <linux/serial_sci.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 enum {
        UNUSED = 0,
@@ -271,7 +272,7 @@ static struct platform_device *sh7760_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7760_early_devices,
+       sh_early_platform_add_devices(sh7760_early_devices,
                                   ARRAY_SIZE(sh7760_early_devices));
 }
 
index a15e25690b5f96a3a78e3dead849228e5eafac77..b6015188fab1f1b58a11101c8b73c8567c11f5db 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <asm/clock.h>
+#include <asm/platform_early.h>
 
 /* Serial */
 static struct plat_sci_port scif0_platform_data = {
@@ -296,7 +297,7 @@ static struct platform_device *sh7343_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7343_early_devices,
+       sh_early_platform_add_devices(sh7343_early_devices,
                                   ARRAY_SIZE(sh7343_early_devices));
 }
 
index 7bd2776441ba0981701dbb2b97122fa9ed32ff93..6676beef053e59e29db75eb58c23c1cb4fb1d133 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sh_intc.h>
 #include <linux/usb/r8a66597.h>
 #include <asm/clock.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE,
@@ -240,7 +241,7 @@ static struct platform_device *sh7366_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7366_early_devices,
+       sh_early_platform_add_devices(sh7366_early_devices,
                                   ARRAY_SIZE(sh7366_early_devices));
 }
 
index 1ce65f88f060e7350041dba893388a3d8eef05e2..0c6757ef63f42c4db50276c23ab551f61a7677ab 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/clock.h>
 #include <asm/mmzone.h>
 #include <asm/siu.h>
+#include <asm/platform_early.h>
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7722.h>
@@ -512,7 +513,7 @@ static struct platform_device *sh7722_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7722_early_devices,
+       sh_early_platform_add_devices(sh7722_early_devices,
                                   ARRAY_SIZE(sh7722_early_devices));
 }
 
index edb6499506625a74e2b52b7efc233653d08047d6..83ae1ad4a86e86b710cf5872d9fd68693f41557c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 #include <cpu/sh7723.h>
 
 /* Serial */
@@ -410,7 +411,7 @@ static struct platform_device *sh7723_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7723_early_devices,
+       sh_early_platform_add_devices(sh7723_early_devices,
                                   ARRAY_SIZE(sh7723_early_devices));
 }
 
index 3e9825031d3d76801a73f26b7675740743f2561d..0d990ab1ba2a9ed743e0fa9fa1d627352e141312 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/suspend.h>
 #include <asm/clock.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 
 #include <cpu/dma-register.h>
 #include <cpu/sh7724.h>
@@ -830,7 +831,7 @@ static struct platform_device *sh7724_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7724_early_devices,
+       sh_early_platform_add_devices(sh7724_early_devices,
                                   ARRAY_SIZE(sh7724_early_devices));
 }
 
index 06a91569697a7c697a2a6f4d92b6bf749690efb9..9911da794358d0b5b000c59439979e01ad9df638 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <asm/clock.h>
 #include <asm/irq.h>
+#include <asm/platform_early.h>
 #include <cpu/sh7734.h>
 
 /* SCIF */
@@ -280,7 +281,7 @@ static struct platform_device *sh7734_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7734_early_devices,
+       sh_early_platform_add_devices(sh7734_early_devices,
                ARRAY_SIZE(sh7734_early_devices));
 }
 
index 2501ce656511b061bbe843831e31a7d77a955641..67e330b7ea4621e98ea5d7c11cea9fc260d82530 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/usb/ohci_pdriver.h>
 #include <cpu/dma-register.h>
 #include <cpu/sh7757.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif2_platform_data = {
        .scscr          = SCSCR_REIE,
@@ -767,7 +768,7 @@ static struct platform_device *sh7757_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7757_early_devices,
+       sh_early_platform_add_devices(sh7757_early_devices,
                                   ARRAY_SIZE(sh7757_early_devices));
 }
 
index 419c5efe4a17fee24308ff77df5707bedeff6fe3..b0608664785f5016e8990e7b614e287eb42bf123 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/serial_sci.h>
 #include <linux/usb/ohci_pdriver.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE,
@@ -221,7 +222,7 @@ static struct platform_device *sh7763_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7763_early_devices,
+       sh_early_platform_add_devices(sh7763_early_devices,
                                   ARRAY_SIZE(sh7763_early_devices));
 }
 
index 5fb4cf9b58c691110ad41bff5dcc55f53e6e00e1..5efec6ceb04d5cc9e4f28dcd2f977b9b1f5181d8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <linux/io.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE | SCSCR_TOIE,
@@ -316,7 +317,7 @@ static struct platform_device *sh7770_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7770_early_devices,
+       sh_early_platform_add_devices(sh7770_early_devices,
                                   ARRAY_SIZE(sh7770_early_devices));
 }
 
index ab7d6b715865b54c07052660dfb960b4455bf832..c818b788ecb05a54f454a8ef6db86dd0ca50d48d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <cpu/dma-register.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE | SCSCR_CKE1,
@@ -285,7 +286,7 @@ void __init plat_early_device_setup(void)
                scif1_platform_data.scscr &= ~SCSCR_CKE1;
        }
 
-       early_platform_add_devices(sh7780_early_devices,
+       sh_early_platform_add_devices(sh7780_early_devices,
                                   ARRAY_SIZE(sh7780_early_devices));
 }
 
index a438da47285d6ceea28a5ff3c6609e2c93eb3e98..3b4a414d60a91c733eeaced87349cade611687d4 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sh_timer.h>
 #include <linux/sh_intc.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 #include <cpu/dma-register.h>
 
 static struct plat_sci_port scif0_platform_data = {
@@ -353,7 +354,7 @@ static struct platform_device *sh7785_early_devices[] __initdata = {
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7785_early_devices,
+       sh_early_platform_add_devices(sh7785_early_devices,
                                   ARRAY_SIZE(sh7785_early_devices));
 }
 
index d894165a0ef6fb8ed16a94bd437501381e4b5ae9..4b0db8259e3d708205c6bdd2fde413a4c3a04608 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/usb/ohci_pdriver.h>
 #include <cpu/dma-register.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .scscr          = SCSCR_REIE | SCSCR_CKE1,
@@ -834,6 +835,6 @@ arch_initcall(sh7786_devices_setup);
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh7786_early_devices,
+       sh_early_platform_add_devices(sh7786_early_devices,
                                   ARRAY_SIZE(sh7786_early_devices));
 }
index 14aa4552bc45b5f75753f8aa2445f7795cd92467..7014d6d199b3e64a67f6444c81bf75a9d2db921d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sh_intc.h>
 #include <cpu/shx3.h>
 #include <asm/mmzone.h>
+#include <asm/platform_early.h>
 
 /*
  * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
@@ -152,7 +153,7 @@ arch_initcall(shx3_devices_setup);
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(shx3_early_devices,
+       sh_early_platform_add_devices(shx3_early_devices,
                                   ARRAY_SIZE(shx3_early_devices));
 }
 
index 41c1673afc0b4301a6e4b56b4530c01411fe614d..dc8476d67244069e8b6088b4bdf95a41ff96a2c8 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/sh_timer.h>
 #include <asm/addrspace.h>
+#include <asm/platform_early.h>
 
 static struct plat_sci_port scif0_platform_data = {
        .flags          = UPF_IOREMAP,
@@ -115,6 +116,6 @@ arch_initcall(sh5_devices_setup);
 
 void __init plat_early_device_setup(void)
 {
-       early_platform_add_devices(sh5_early_devices,
+       sh_early_platform_add_devices(sh5_early_devices,
                                   ARRAY_SIZE(sh5_early_devices));
 }
index 2c0e0f37a318d3ad6f2628df398bb5d1c54f5f72..914174a125a43fc4b801910177b12efdbf6a92e5 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/mmu_context.h>
 #include <asm/mmzone.h>
 #include <asm/sparsemem.h>
+#include <asm/platform_early.h>
 
 /*
  * Initialize loops_per_jiffy as 10000000 (1000MIPS).
@@ -328,7 +329,7 @@ void __init setup_arch(char **cmdline_p)
        sh_mv_setup();
 
        /* Let earlyprintk output early console messages */
-       early_platform_driver_probe("earlyprintk", 1, 1);
+       sh_early_platform_driver_probe("earlyprintk", 1, 1);
 
 #ifdef CONFIG_OF_FLATTREE
 #ifdef CONFIG_USE_BUILTIN_DTB
index e16b2cd269a331f911a02a35de7170e67922a382..821a09cbd6054f6d089d6f3062531b7325a7135d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/rtc.h>
 #include <asm/clock.h>
 #include <asm/rtc.h>
+#include <asm/platform_early.h>
 
 static void __init sh_late_time_init(void)
 {
@@ -30,8 +31,8 @@ static void __init sh_late_time_init(void)
         * clocksource and the jiffies clocksource is used transparently
         * instead. No error handling is necessary here.
         */
-       early_platform_driver_register_all("earlytimer");
-       early_platform_driver_probe("earlytimer", 2, 0);
+       sh_early_platform_driver_register_all("earlytimer");
+       sh_early_platform_driver_probe("earlytimer", 2, 0);
 }
 
 void __init time_init(void)
index 7bd9cd366d41193638c858076755eec4ab1c67e6..e6d3e6d485daab3d8801b887df111a609ac34064 100644 (file)
@@ -45,6 +45,10 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup);
 #endif
 
 /* Device links support. */
+static LIST_HEAD(wait_for_suppliers);
+static DEFINE_MUTEX(wfs_lock);
+static LIST_HEAD(deferred_sync);
+static unsigned int defer_sync_state_count = 1;
 
 #ifdef CONFIG_SRCU
 static DEFINE_MUTEX(device_links_lock);
@@ -127,6 +131,9 @@ static int device_is_dependent(struct device *dev, void *target)
                return ret;
 
        list_for_each_entry(link, &dev->links.consumers, s_node) {
+               if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
+                       continue;
+
                if (link->consumer == target)
                        return 1;
 
@@ -196,8 +203,11 @@ static int device_reorder_to_tail(struct device *dev, void *not_used)
                device_pm_move_last(dev);
 
        device_for_each_child(dev, NULL, device_reorder_to_tail);
-       list_for_each_entry(link, &dev->links.consumers, s_node)
+       list_for_each_entry(link, &dev->links.consumers, s_node) {
+               if (link->flags == (DL_FLAG_SYNC_STATE_ONLY | DL_FLAG_MANAGED))
+                       continue;
                device_reorder_to_tail(link->consumer, NULL);
+       }
 
        return 0;
 }
@@ -224,7 +234,8 @@ void device_pm_move_to_tail(struct device *dev)
 
 #define DL_MANAGED_LINK_FLAGS (DL_FLAG_AUTOREMOVE_CONSUMER | \
                               DL_FLAG_AUTOREMOVE_SUPPLIER | \
-                              DL_FLAG_AUTOPROBE_CONSUMER)
+                              DL_FLAG_AUTOPROBE_CONSUMER  | \
+                              DL_FLAG_SYNC_STATE_ONLY)
 
 #define DL_ADD_VALID_FLAGS (DL_MANAGED_LINK_FLAGS | DL_FLAG_STATELESS | \
                            DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE)
@@ -292,6 +303,8 @@ struct device_link *device_link_add(struct device *consumer,
 
        if (!consumer || !supplier || flags & ~DL_ADD_VALID_FLAGS ||
            (flags & DL_FLAG_STATELESS && flags & DL_MANAGED_LINK_FLAGS) ||
+           (flags & DL_FLAG_SYNC_STATE_ONLY &&
+            flags != DL_FLAG_SYNC_STATE_ONLY) ||
            (flags & DL_FLAG_AUTOPROBE_CONSUMER &&
             flags & (DL_FLAG_AUTOREMOVE_CONSUMER |
                      DL_FLAG_AUTOREMOVE_SUPPLIER)))
@@ -312,11 +325,14 @@ struct device_link *device_link_add(struct device *consumer,
 
        /*
         * If the supplier has not been fully registered yet or there is a
-        * reverse dependency between the consumer and the supplier already in
-        * the graph, return NULL.
+        * reverse (non-SYNC_STATE_ONLY) dependency between the consumer and
+        * the supplier already in the graph, return NULL. If the link is a
+        * SYNC_STATE_ONLY link, we don't check for reverse dependencies
+        * because it only affects sync_state() callbacks.
         */
        if (!device_pm_initialized(supplier)
-           || device_is_dependent(consumer, supplier)) {
+           || (!(flags & DL_FLAG_SYNC_STATE_ONLY) &&
+                 device_is_dependent(consumer, supplier))) {
                link = NULL;
                goto out;
        }
@@ -343,9 +359,14 @@ struct device_link *device_link_add(struct device *consumer,
                }
 
                if (flags & DL_FLAG_STATELESS) {
-                       link->flags |= DL_FLAG_STATELESS;
                        kref_get(&link->kref);
-                       goto out;
+                       if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
+                           !(link->flags & DL_FLAG_STATELESS)) {
+                               link->flags |= DL_FLAG_STATELESS;
+                               goto reorder;
+                       } else {
+                               goto out;
+                       }
                }
 
                /*
@@ -367,6 +388,12 @@ struct device_link *device_link_add(struct device *consumer,
                        link->flags |= DL_FLAG_MANAGED;
                        device_link_init_status(link, consumer, supplier);
                }
+               if (link->flags & DL_FLAG_SYNC_STATE_ONLY &&
+                   !(flags & DL_FLAG_SYNC_STATE_ONLY)) {
+                       link->flags &= ~DL_FLAG_SYNC_STATE_ONLY;
+                       goto reorder;
+               }
+
                goto out;
        }
 
@@ -406,6 +433,13 @@ struct device_link *device_link_add(struct device *consumer,
            flags & DL_FLAG_PM_RUNTIME)
                pm_runtime_resume(supplier);
 
+       if (flags & DL_FLAG_SYNC_STATE_ONLY) {
+               dev_dbg(consumer,
+                       "Linked as a sync state only consumer to %s\n",
+                       dev_name(supplier));
+               goto out;
+       }
+reorder:
        /*
         * Move the consumer and all of the devices depending on it to the end
         * of dpm_list and the devices_kset list.
@@ -431,6 +465,70 @@ struct device_link *device_link_add(struct device *consumer,
 }
 EXPORT_SYMBOL_GPL(device_link_add);
 
+/**
+ * device_link_wait_for_supplier - Add device to wait_for_suppliers list
+ * @consumer: Consumer device
+ *
+ * Marks the @consumer device as waiting for suppliers to become available by
+ * adding it to the wait_for_suppliers list. The consumer device will never be
+ * probed until it's removed from the wait_for_suppliers list.
+ *
+ * The caller is responsible for adding the links to the supplier devices once
+ * they are available and removing the @consumer device from the
+ * wait_for_suppliers list once links to all the suppliers have been created.
+ *
+ * This function is NOT meant to be called from the probe function of the
+ * consumer but rather from code that creates/adds the consumer device.
+ */
+static void device_link_wait_for_supplier(struct device *consumer,
+                                         bool need_for_probe)
+{
+       mutex_lock(&wfs_lock);
+       list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers);
+       consumer->links.need_for_probe = need_for_probe;
+       mutex_unlock(&wfs_lock);
+}
+
+static void device_link_wait_for_mandatory_supplier(struct device *consumer)
+{
+       device_link_wait_for_supplier(consumer, true);
+}
+
+static void device_link_wait_for_optional_supplier(struct device *consumer)
+{
+       device_link_wait_for_supplier(consumer, false);
+}
+
+/**
+ * device_link_add_missing_supplier_links - Add links from consumer devices to
+ *                                         supplier devices, leaving any
+ *                                         consumer with inactive suppliers on
+ *                                         the wait_for_suppliers list
+ *
+ * Loops through all consumers waiting on suppliers and tries to add all their
+ * supplier links. If that succeeds, the consumer device is removed from
+ * wait_for_suppliers list. Otherwise, they are left in the wait_for_suppliers
+ * list.  Devices left on the wait_for_suppliers list will not be probed.
+ *
+ * The fwnode add_links callback is expected to return 0 if it has found and
+ * added all the supplier links for the consumer device. It should return an
+ * error if it isn't able to do so.
+ *
+ * The caller of device_link_wait_for_supplier() is expected to call this once
+ * it's aware of potential suppliers becoming available.
+ */
+static void device_link_add_missing_supplier_links(void)
+{
+       struct device *dev, *tmp;
+
+       mutex_lock(&wfs_lock);
+       list_for_each_entry_safe(dev, tmp, &wait_for_suppliers,
+                                links.needs_suppliers)
+               if (!fwnode_call_int_op(dev->fwnode, add_links, dev))
+                       list_del_init(&dev->links.needs_suppliers);
+       mutex_unlock(&wfs_lock);
+}
+
 static void device_link_free(struct device_link *link)
 {
        while (refcount_dec_not_one(&link->rpm_active))
@@ -565,10 +663,23 @@ int device_links_check_suppliers(struct device *dev)
        struct device_link *link;
        int ret = 0;
 
+       /*
+        * Device waiting for supplier to become available is not allowed to
+        * probe.
+        */
+       mutex_lock(&wfs_lock);
+       if (!list_empty(&dev->links.needs_suppliers) &&
+           dev->links.need_for_probe) {
+               mutex_unlock(&wfs_lock);
+               return -EPROBE_DEFER;
+       }
+       mutex_unlock(&wfs_lock);
+
        device_links_write_lock();
 
        list_for_each_entry(link, &dev->links.suppliers, c_node) {
-               if (!(link->flags & DL_FLAG_MANAGED))
+               if (!(link->flags & DL_FLAG_MANAGED) ||
+                   link->flags & DL_FLAG_SYNC_STATE_ONLY)
                        continue;
 
                if (link->status != DL_STATE_AVAILABLE) {
@@ -584,6 +695,69 @@ int device_links_check_suppliers(struct device *dev)
        return ret;
 }
 
+static void __device_links_supplier_sync_state(struct device *dev)
+{
+       struct device_link *link;
+
+       if (dev->state_synced)
+               return;
+
+       list_for_each_entry(link, &dev->links.consumers, s_node) {
+               if (!(link->flags & DL_FLAG_MANAGED))
+                       continue;
+               if (link->status != DL_STATE_ACTIVE)
+                       return;
+       }
+
+       if (dev->bus->sync_state)
+               dev->bus->sync_state(dev);
+       else if (dev->driver && dev->driver->sync_state)
+               dev->driver->sync_state(dev);
+
+       dev->state_synced = true;
+}
+
+void device_links_supplier_sync_state_pause(void)
+{
+       device_links_write_lock();
+       defer_sync_state_count++;
+       device_links_write_unlock();
+}
+
+void device_links_supplier_sync_state_resume(void)
+{
+       struct device *dev, *tmp;
+
+       device_links_write_lock();
+       if (!defer_sync_state_count) {
+               WARN(true, "Unmatched sync_state pause/resume!");
+               goto out;
+       }
+       defer_sync_state_count--;
+       if (defer_sync_state_count)
+               goto out;
+
+       list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_sync) {
+               __device_links_supplier_sync_state(dev);
+               list_del_init(&dev->links.defer_sync);
+       }
+out:
+       device_links_write_unlock();
+}
+
+static int sync_state_resume_initcall(void)
+{
+       device_links_supplier_sync_state_resume();
+       return 0;
+}
+late_initcall(sync_state_resume_initcall);
+
+static void __device_links_supplier_defer_sync(struct device *sup)
+{
+       if (list_empty(&sup->links.defer_sync))
+               list_add_tail(&sup->links.defer_sync, &deferred_sync);
+}
+
 /**
  * device_links_driver_bound - Update device links after probing its driver.
  * @dev: Device to update the links for.
@@ -599,6 +773,15 @@ void device_links_driver_bound(struct device *dev)
 {
        struct device_link *link;
 
+       /*
+        * If a device probes successfully, it's expected to have created all
+        * the device links it needs to or make new device links as it needs
+        * them. So, it no longer needs to wait on any suppliers.
+        */
+       mutex_lock(&wfs_lock);
+       list_del_init(&dev->links.needs_suppliers);
+       mutex_unlock(&wfs_lock);
+
        device_links_write_lock();
 
        list_for_each_entry(link, &dev->links.consumers, s_node) {
@@ -628,6 +811,11 @@ void device_links_driver_bound(struct device *dev)
 
                WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);
                WRITE_ONCE(link->status, DL_STATE_ACTIVE);
+
+               if (defer_sync_state_count)
+                       __device_links_supplier_defer_sync(link->supplier);
+               else
+                       __device_links_supplier_sync_state(link->supplier);
        }
 
        dev->links.status = DL_DEV_DRIVER_BOUND;
@@ -744,6 +932,7 @@ void device_links_driver_cleanup(struct device *dev)
                WRITE_ONCE(link->status, DL_STATE_DORMANT);
        }
 
+       list_del_init(&dev->links.defer_sync);
        __device_links_no_driver(dev);
 
        device_links_write_unlock();
@@ -813,7 +1002,8 @@ void device_links_unbind_consumers(struct device *dev)
        list_for_each_entry(link, &dev->links.consumers, s_node) {
                enum device_link_state status;
 
-               if (!(link->flags & DL_FLAG_MANAGED))
+               if (!(link->flags & DL_FLAG_MANAGED) ||
+                   link->flags & DL_FLAG_SYNC_STATE_ONLY)
                        continue;
 
                status = link->status;
@@ -849,6 +1039,10 @@ static void device_links_purge(struct device *dev)
 {
        struct device_link *link, *ln;
 
+       mutex_lock(&wfs_lock);
+       list_del(&dev->links.needs_suppliers);
+       mutex_unlock(&wfs_lock);
+
        /*
         * Delete all of the remaining links from this device to any other
         * devices (either consumers or suppliers).
@@ -1713,6 +1907,8 @@ void device_initialize(struct device *dev)
 #endif
        INIT_LIST_HEAD(&dev->links.consumers);
        INIT_LIST_HEAD(&dev->links.suppliers);
+       INIT_LIST_HEAD(&dev->links.needs_suppliers);
+       INIT_LIST_HEAD(&dev->links.defer_sync);
        dev->links.status = DL_DEV_NO_DRIVER;
 }
 EXPORT_SYMBOL_GPL(device_initialize);
@@ -2101,7 +2297,7 @@ int device_add(struct device *dev)
        struct device *parent;
        struct kobject *kobj;
        struct class_interface *class_intf;
-       int error = -EINVAL;
+       int error = -EINVAL, fw_ret;
        struct kobject *glue_dir = NULL;
 
        dev = get_device(dev);
@@ -2199,6 +2395,32 @@ int device_add(struct device *dev)
                                             BUS_NOTIFY_ADD_DEVICE, dev);
 
        kobject_uevent(&dev->kobj, KOBJ_ADD);
+
+       if (dev->fwnode && !dev->fwnode->dev)
+               dev->fwnode->dev = dev;
+
+       /*
+        * Check if any of the other devices (consumers) have been waiting for
+        * this device (supplier) to be added so that they can create a device
+        * link to it.
+        *
+        * This needs to happen after device_pm_add() because device_link_add()
+        * requires the supplier be registered before it's called.
+        *
+        * But this also needs to happe before bus_probe_device() to make sure
+        * waiting consumers can link to it before the driver is bound to the
+        * device and the driver sync_state callback is called for this device.
+        */
+       device_link_add_missing_supplier_links();
+
+       if (fwnode_has_op(dev->fwnode, add_links)) {
+               fw_ret = fwnode_call_int_op(dev->fwnode, add_links, dev);
+               if (fw_ret == -ENODEV)
+                       device_link_wait_for_mandatory_supplier(dev);
+               else if (fw_ret)
+                       device_link_wait_for_optional_supplier(dev);
+       }
+
        bus_probe_device(dev);
        if (parent)
                klist_add_tail(&dev->p->knode_parent,
@@ -2343,6 +2565,9 @@ void device_del(struct device *dev)
        kill_device(dev);
        device_unlock(dev);
 
+       if (dev->fwnode && dev->fwnode->dev == dev)
+               dev->fwnode->dev = NULL;
+
        /* Notify clients of device removal.  This call must come
         * before dpm_sysfs_remove().
         */
index bf44c79beae92b23fbc63b011da722abcc88f040..7302e6bc419b54e5fe9a56544113225161d1103f 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Copyright (c) 2003 Manuel Estrada Sainz
  *
- * Please see Documentation/firmware_class/ for more information.
+ * Please see Documentation/driver-api/firmware/ for more information.
  *
  */
 
@@ -504,6 +504,7 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
                                         path);
                        continue;
                }
+               dev_dbg(device, "Loading firmware from %s\n", path);
                if (decompress) {
                        dev_dbg(device, "f/w decompressing %s\n",
                                fw_priv->fw_name);
index b230beb6ccb41ba8beb5fbaf87972f69b94a33e3..1b8a20466eef278c382a0d44f8f54a37aaa1a254 100644 (file)
@@ -60,6 +60,7 @@ struct resource *platform_get_resource(struct platform_device *dev,
 }
 EXPORT_SYMBOL_GPL(platform_get_resource);
 
+#ifdef CONFIG_HAS_IOMEM
 /**
  * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform
  *                                 device
@@ -68,7 +69,6 @@ EXPORT_SYMBOL_GPL(platform_get_resource);
  *        resource management
  * @index: resource index
  */
-#ifdef CONFIG_HAS_IOMEM
 void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
                                             unsigned int index)
 {
@@ -78,9 +78,63 @@ void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
        return devm_ioremap_resource(&pdev->dev, res);
 }
 EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource);
+
+/**
+ * devm_platform_ioremap_resource_wc - write-combined variant of
+ *                                     devm_platform_ioremap_resource()
+ *
+ * @pdev: platform device to use both for memory resource lookup as well as
+ *        resource management
+ * @index: resource index
+ */
+void __iomem *devm_platform_ioremap_resource_wc(struct platform_device *pdev,
+                                               unsigned int index)
+{
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, index);
+       return devm_ioremap_resource_wc(&pdev->dev, res);
+}
+
+/**
+ * devm_platform_ioremap_resource_byname - call devm_ioremap_resource for
+ *                                        a platform device, retrieve the
+ *                                        resource by name
+ *
+ * @pdev: platform device to use both for memory resource lookup as well as
+ *       resource management
+ * @name: name of the resource
+ */
+void __iomem *
+devm_platform_ioremap_resource_byname(struct platform_device *pdev,
+                                     const char *name)
+{
+       struct resource *res;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       return devm_ioremap_resource(&pdev->dev, res);
+}
+EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
 #endif /* CONFIG_HAS_IOMEM */
 
-static int __platform_get_irq(struct platform_device *dev, unsigned int num)
+/**
+ * platform_get_irq_optional - get an optional IRQ for a device
+ * @dev: platform device
+ * @num: IRQ number index
+ *
+ * Gets an IRQ for a platform device. Device drivers should check the return
+ * value for errors so as to not pass a negative integer value to the
+ * request_irq() APIs. This is the same as platform_get_irq(), except that it
+ * does not print an error message if an IRQ can not be obtained.
+ *
+ * Example:
+ *             int irq = platform_get_irq_optional(pdev, 0);
+ *             if (irq < 0)
+ *                     return irq;
+ *
+ * Return: IRQ number on success, negative error number on failure.
+ */
+int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
 {
 #ifdef CONFIG_SPARC
        /* sparc does not have irqs represented as IORESOURCE_IRQ resources */
@@ -144,6 +198,7 @@ static int __platform_get_irq(struct platform_device *dev, unsigned int num)
        return -ENXIO;
 #endif
 }
+EXPORT_SYMBOL_GPL(platform_get_irq_optional);
 
 /**
  * platform_get_irq - get an IRQ for a device
@@ -165,7 +220,7 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
 {
        int ret;
 
-       ret = __platform_get_irq(dev, num);
+       ret = platform_get_irq_optional(dev, num);
        if (ret < 0 && ret != -EPROBE_DEFER)
                dev_err(&dev->dev, "IRQ index %u not found\n", num);
 
@@ -173,29 +228,6 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
 }
 EXPORT_SYMBOL_GPL(platform_get_irq);
 
-/**
- * platform_get_irq_optional - get an optional IRQ for a device
- * @dev: platform device
- * @num: IRQ number index
- *
- * Gets an IRQ for a platform device. Device drivers should check the return
- * value for errors so as to not pass a negative integer value to the
- * request_irq() APIs. This is the same as platform_get_irq(), except that it
- * does not print an error message if an IRQ can not be obtained.
- *
- * Example:
- *             int irq = platform_get_irq_optional(pdev, 0);
- *             if (irq < 0)
- *                     return irq;
- *
- * Return: IRQ number on success, negative error number on failure.
- */
-int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
-{
-       return __platform_get_irq(dev, num);
-}
-EXPORT_SYMBOL_GPL(platform_get_irq_optional);
-
 /**
  * platform_irq_count - Count the number of IRQs a platform device uses
  * @dev: platform device
@@ -206,7 +238,7 @@ int platform_irq_count(struct platform_device *dev)
 {
        int ret, nr = 0;
 
-       while ((ret = __platform_get_irq(dev, nr)) >= 0)
+       while ((ret = platform_get_irq_optional(dev, nr)) >= 0)
                nr++;
 
        if (ret == -EPROBE_DEFER)
@@ -1296,8 +1328,6 @@ int __init platform_bus_init(void)
 {
        int error;
 
-       early_platform_cleanup();
-
        error = device_register(&platform_bus);
        if (error) {
                put_device(&platform_bus);
@@ -1309,289 +1339,3 @@ int __init platform_bus_init(void)
        of_platform_register_reconfig_notifier();
        return error;
 }
-
-static __initdata LIST_HEAD(early_platform_driver_list);
-static __initdata LIST_HEAD(early_platform_device_list);
-
-/**
- * early_platform_driver_register - register early platform driver
- * @epdrv: early_platform driver structure
- * @buf: string passed from early_param()
- *
- * Helper function for early_platform_init() / early_platform_init_buffer()
- */
-int __init early_platform_driver_register(struct early_platform_driver *epdrv,
-                                         char *buf)
-{
-       char *tmp;
-       int n;
-
-       /* Simply add the driver to the end of the global list.
-        * Drivers will by default be put on the list in compiled-in order.
-        */
-       if (!epdrv->list.next) {
-               INIT_LIST_HEAD(&epdrv->list);
-               list_add_tail(&epdrv->list, &early_platform_driver_list);
-       }
-
-       /* If the user has specified device then make sure the driver
-        * gets prioritized. The driver of the last device specified on
-        * command line will be put first on the list.
-        */
-       n = strlen(epdrv->pdrv->driver.name);
-       if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) {
-               list_move(&epdrv->list, &early_platform_driver_list);
-
-               /* Allow passing parameters after device name */
-               if (buf[n] == '\0' || buf[n] == ',')
-                       epdrv->requested_id = -1;
-               else {
-                       epdrv->requested_id = simple_strtoul(&buf[n + 1],
-                                                            &tmp, 10);
-
-                       if (buf[n] != '.' || (tmp == &buf[n + 1])) {
-                               epdrv->requested_id = EARLY_PLATFORM_ID_ERROR;
-                               n = 0;
-                       } else
-                               n += strcspn(&buf[n + 1], ",") + 1;
-               }
-
-               if (buf[n] == ',')
-                       n++;
-
-               if (epdrv->bufsize) {
-                       memcpy(epdrv->buffer, &buf[n],
-                              min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1));
-                       epdrv->buffer[epdrv->bufsize - 1] = '\0';
-               }
-       }
-
-       return 0;
-}
-
-/**
- * early_platform_add_devices - adds a number of early platform devices
- * @devs: array of early platform devices to add
- * @num: number of early platform devices in array
- *
- * Used by early architecture code to register early platform devices and
- * their platform data.
- */
-void __init early_platform_add_devices(struct platform_device **devs, int num)
-{
-       struct device *dev;
-       int i;
-
-       /* simply add the devices to list */
-       for (i = 0; i < num; i++) {
-               dev = &devs[i]->dev;
-
-               if (!dev->devres_head.next) {
-                       pm_runtime_early_init(dev);
-                       INIT_LIST_HEAD(&dev->devres_head);
-                       list_add_tail(&dev->devres_head,
-                                     &early_platform_device_list);
-               }
-       }
-}
-
-/**
- * early_platform_driver_register_all - register early platform drivers
- * @class_str: string to identify early platform driver class
- *
- * Used by architecture code to register all early platform drivers
- * for a certain class. If omitted then only early platform drivers
- * with matching kernel command line class parameters will be registered.
- */
-void __init early_platform_driver_register_all(char *class_str)
-{
-       /* The "class_str" parameter may or may not be present on the kernel
-        * command line. If it is present then there may be more than one
-        * matching parameter.
-        *
-        * Since we register our early platform drivers using early_param()
-        * we need to make sure that they also get registered in the case
-        * when the parameter is missing from the kernel command line.
-        *
-        * We use parse_early_options() to make sure the early_param() gets
-        * called at least once. The early_param() may be called more than
-        * once since the name of the preferred device may be specified on
-        * the kernel command line. early_platform_driver_register() handles
-        * this case for us.
-        */
-       parse_early_options(class_str);
-}
-
-/**
- * early_platform_match - find early platform device matching driver
- * @epdrv: early platform driver structure
- * @id: id to match against
- */
-static struct platform_device * __init
-early_platform_match(struct early_platform_driver *epdrv, int id)
-{
-       struct platform_device *pd;
-
-       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
-               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
-                       if (pd->id == id)
-                               return pd;
-
-       return NULL;
-}
-
-/**
- * early_platform_left - check if early platform driver has matching devices
- * @epdrv: early platform driver structure
- * @id: return true if id or above exists
- */
-static int __init early_platform_left(struct early_platform_driver *epdrv,
-                                      int id)
-{
-       struct platform_device *pd;
-
-       list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
-               if (platform_match(&pd->dev, &epdrv->pdrv->driver))
-                       if (pd->id >= id)
-                               return 1;
-
-       return 0;
-}
-
-/**
- * early_platform_driver_probe_id - probe drivers matching class_str and id
- * @class_str: string to identify early platform driver class
- * @id: id to match against
- * @nr_probe: number of platform devices to successfully probe before exiting
- */
-static int __init early_platform_driver_probe_id(char *class_str,
-                                                int id,
-                                                int nr_probe)
-{
-       struct early_platform_driver *epdrv;
-       struct platform_device *match;
-       int match_id;
-       int n = 0;
-       int left = 0;
-
-       list_for_each_entry(epdrv, &early_platform_driver_list, list) {
-               /* only use drivers matching our class_str */
-               if (strcmp(class_str, epdrv->class_str))
-                       continue;
-
-               if (id == -2) {
-                       match_id = epdrv->requested_id;
-                       left = 1;
-
-               } else {
-                       match_id = id;
-                       left += early_platform_left(epdrv, id);
-
-                       /* skip requested id */
-                       switch (epdrv->requested_id) {
-                       case EARLY_PLATFORM_ID_ERROR:
-                       case EARLY_PLATFORM_ID_UNSET:
-                               break;
-                       default:
-                               if (epdrv->requested_id == id)
-                                       match_id = EARLY_PLATFORM_ID_UNSET;
-                       }
-               }
-
-               switch (match_id) {
-               case EARLY_PLATFORM_ID_ERROR:
-                       pr_warn("%s: unable to parse %s parameter\n",
-                               class_str, epdrv->pdrv->driver.name);
-                       /* fall-through */
-               case EARLY_PLATFORM_ID_UNSET:
-                       match = NULL;
-                       break;
-               default:
-                       match = early_platform_match(epdrv, match_id);
-               }
-
-               if (match) {
-                       /*
-                        * Set up a sensible init_name to enable
-                        * dev_name() and others to be used before the
-                        * rest of the driver core is initialized.
-                        */
-                       if (!match->dev.init_name && slab_is_available()) {
-                               if (match->id != -1)
-                                       match->dev.init_name =
-                                               kasprintf(GFP_KERNEL, "%s.%d",
-                                                         match->name,
-                                                         match->id);
-                               else
-                                       match->dev.init_name =
-                                               kasprintf(GFP_KERNEL, "%s",
-                                                         match->name);
-
-                               if (!match->dev.init_name)
-                                       return -ENOMEM;
-                       }
-
-                       if (epdrv->pdrv->probe(match))
-                               pr_warn("%s: unable to probe %s early.\n",
-                                       class_str, match->name);
-                       else
-                               n++;
-               }
-
-               if (n >= nr_probe)
-                       break;
-       }
-
-       if (left)
-               return n;
-       else
-               return -ENODEV;
-}
-
-/**
- * early_platform_driver_probe - probe a class of registered drivers
- * @class_str: string to identify early platform driver class
- * @nr_probe: number of platform devices to successfully probe before exiting
- * @user_only: only probe user specified early platform devices
- *
- * Used by architecture code to probe registered early platform drivers
- * within a certain class. For probe to happen a registered early platform
- * device matching a registered early platform driver is needed.
- */
-int __init early_platform_driver_probe(char *class_str,
-                                      int nr_probe,
-                                      int user_only)
-{
-       int k, n, i;
-
-       n = 0;
-       for (i = -2; n < nr_probe; i++) {
-               k = early_platform_driver_probe_id(class_str, i, nr_probe - n);
-
-               if (k < 0)
-                       break;
-
-               n += k;
-
-               if (user_only)
-                       break;
-       }
-
-       return n;
-}
-
-/**
- * early_platform_cleanup - clean up early platform code
- */
-void __init early_platform_cleanup(void)
-{
-       struct platform_device *pd, *pd2;
-
-       /* clean up the devres list used to chain devices */
-       list_for_each_entry_safe(pd, pd2, &early_platform_device_list,
-                                dev.devres_head) {
-               list_del(&pd->dev.devres_head);
-               memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head));
-       }
-}
-
index 7c0c5ca5953d20b63b849ec537ba999a328f212a..4af11a423475e5bb818d3b36b2410e25861b786a 100644 (file)
@@ -104,15 +104,12 @@ static const struct attribute_group soc_attr_group = {
        .is_visible = soc_attribute_mode,
 };
 
-static const struct attribute_group *soc_attr_groups[] = {
-       &soc_attr_group,
-       NULL,
-};
-
 static void soc_release(struct device *dev)
 {
        struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
 
+       ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
+       kfree(soc_dev->dev.groups);
        kfree(soc_dev);
 }
 
@@ -121,6 +118,7 @@ static struct soc_device_attribute *early_soc_dev_attr;
 struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
 {
        struct soc_device *soc_dev;
+       const struct attribute_group **soc_attr_groups;
        int ret;
 
        if (!soc_bus_type.p) {
@@ -136,10 +134,18 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
                goto out1;
        }
 
+       soc_attr_groups = kcalloc(3, sizeof(*soc_attr_groups), GFP_KERNEL);
+       if (!soc_attr_groups) {
+               ret = -ENOMEM;
+               goto out2;
+       }
+       soc_attr_groups[0] = &soc_attr_group;
+       soc_attr_groups[1] = soc_dev_attr->custom_attr_group;
+
        /* Fetch a unique (reclaimable) SOC ID. */
        ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL);
        if (ret < 0)
-               goto out2;
+               goto out3;
        soc_dev->soc_dev_num = ret;
 
        soc_dev->attr = soc_dev_attr;
@@ -150,15 +156,15 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
        dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
 
        ret = device_register(&soc_dev->dev);
-       if (ret)
-               goto out3;
+       if (ret) {
+               put_device(&soc_dev->dev);
+               return ERR_PTR(ret);
+       }
 
        return soc_dev;
 
 out3:
-       ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
-       put_device(&soc_dev->dev);
-       soc_dev = NULL;
+       kfree(soc_attr_groups);
 out2:
        kfree(soc_dev);
 out1:
@@ -169,8 +175,6 @@ EXPORT_SYMBOL_GPL(soc_device_register);
 /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
 void soc_device_unregister(struct soc_device *soc_dev)
 {
-       ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
-
        device_unregister(&soc_dev->dev);
        early_soc_dev_attr = NULL;
 }
index ef773db080e903002b693b41b961a2d48e0f5e53..9cde50cb322008a02a1d38c56f68a9a07f923fac 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
 struct sh_cmt_device;
 
 /*
@@ -1052,7 +1056,7 @@ static int sh_cmt_probe(struct platform_device *pdev)
        struct sh_cmt_device *cmt = platform_get_drvdata(pdev);
        int ret;
 
-       if (!is_early_platform_device(pdev)) {
+       if (!is_sh_early_platform_device(pdev)) {
                pm_runtime_set_active(&pdev->dev);
                pm_runtime_enable(&pdev->dev);
        }
@@ -1072,7 +1076,7 @@ static int sh_cmt_probe(struct platform_device *pdev)
                pm_runtime_idle(&pdev->dev);
                return ret;
        }
-       if (is_early_platform_device(pdev))
+       if (is_sh_early_platform_device(pdev))
                return 0;
 
  out:
@@ -1109,7 +1113,10 @@ static void __exit sh_cmt_exit(void)
        platform_driver_unregister(&sh_cmt_device_driver);
 }
 
-early_platform_init("earlytimer", &sh_cmt_device_driver);
+#ifdef CONFIG_SUPERH
+sh_early_platform_init("earlytimer", &sh_cmt_device_driver);
+#endif
+
 subsys_initcall(sh_cmt_init);
 module_exit(sh_cmt_exit);
 
index 354b27d14a19bfcef43656f3555e69a32b28da2d..c40eef091a04dab282914ec79b0209c458842cde 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
 struct sh_mtu2_device;
 
 struct sh_mtu2_channel {
@@ -442,7 +446,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
        struct sh_mtu2_device *mtu = platform_get_drvdata(pdev);
        int ret;
 
-       if (!is_early_platform_device(pdev)) {
+       if (!is_sh_early_platform_device(pdev)) {
                pm_runtime_set_active(&pdev->dev);
                pm_runtime_enable(&pdev->dev);
        }
@@ -462,7 +466,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
                pm_runtime_idle(&pdev->dev);
                return ret;
        }
-       if (is_early_platform_device(pdev))
+       if (is_sh_early_platform_device(pdev))
                return 0;
 
  out:
@@ -511,7 +515,10 @@ static void __exit sh_mtu2_exit(void)
        platform_driver_unregister(&sh_mtu2_device_driver);
 }
 
-early_platform_init("earlytimer", &sh_mtu2_device_driver);
+#ifdef CONFIG_SUPERH
+sh_early_platform_init("earlytimer", &sh_mtu2_device_driver);
+#endif
+
 subsys_initcall(sh_mtu2_init);
 module_exit(sh_mtu2_exit);
 
index 8c4f3753b36ecbec88cb4be5091264e44f6a1934..d49690d1553670e65bede80e78e2e07e648b5ecd 100644 (file)
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#ifdef CONFIG_SUPERH
+#include <asm/platform_early.h>
+#endif
+
 enum sh_tmu_model {
        SH_TMU,
        SH_TMU_SH3,
@@ -595,7 +599,7 @@ static int sh_tmu_probe(struct platform_device *pdev)
        struct sh_tmu_device *tmu = platform_get_drvdata(pdev);
        int ret;
 
-       if (!is_early_platform_device(pdev)) {
+       if (!is_sh_early_platform_device(pdev)) {
                pm_runtime_set_active(&pdev->dev);
                pm_runtime_enable(&pdev->dev);
        }
@@ -615,7 +619,8 @@ static int sh_tmu_probe(struct platform_device *pdev)
                pm_runtime_idle(&pdev->dev);
                return ret;
        }
-       if (is_early_platform_device(pdev))
+
+       if (is_sh_early_platform_device(pdev))
                return 0;
 
  out:
@@ -665,7 +670,10 @@ static void __exit sh_tmu_exit(void)
        platform_driver_unregister(&sh_tmu_device_driver);
 }
 
-early_platform_init("earlytimer", &sh_tmu_device_driver);
+#ifdef CONFIG_SUPERH
+sh_early_platform_init("earlytimer", &sh_tmu_device_driver);
+#endif
+
 subsys_initcall(sh_tmu_init);
 module_exit(sh_tmu_exit);
 
index 734be6b752d0d85b9769913511c64b671b294304..88ab3bc85aac4ca51ee424454e6b3571cd6372ce 100644 (file)
@@ -232,3 +232,4 @@ module_platform_driver(bd70528_gpio);
 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
 MODULE_DESCRIPTION("BD70528 voltage regulator driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bd70528-gpio");
index 674ebebaf90b6459af311064bc5c0d19674d3ab7..17a243c528adeaf8f1b67c258ee55988310c5eb0 100644 (file)
@@ -269,13 +269,12 @@ static void em_gio_irq_domain_remove(void *data)
 static int em_gio_probe(struct platform_device *pdev)
 {
        struct em_gio_priv *p;
-       struct resource *irq[2];
        struct gpio_chip *gpio_chip;
        struct irq_chip *irq_chip;
        struct device *dev = &pdev->dev;
        const char *name = dev_name(dev);
        unsigned int ngpios;
-       int ret;
+       int irq[2], ret;
 
        p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
        if (!p)
@@ -285,13 +284,13 @@ static int em_gio_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, p);
        spin_lock_init(&p->sense_lock);
 
-       irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       irq[0] = platform_get_irq(pdev, 0);
+       if (irq[0] < 0)
+               return irq[0];
 
-       if (!irq[0] || !irq[1]) {
-               dev_err(dev, "missing IRQ or IOMEM\n");
-               return -EINVAL;
-       }
+       irq[1] = platform_get_irq(pdev, 1);
+       if (irq[1] < 0)
+               return irq[1];
 
        p->base0 = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(p->base0))
@@ -322,7 +321,7 @@ static int em_gio_probe(struct platform_device *pdev)
        gpio_chip->ngpio = ngpios;
 
        irq_chip = &p->irq_chip;
-       irq_chip->name = name;
+       irq_chip->name = "gpio-em";
        irq_chip->irq_mask = em_gio_irq_disable;
        irq_chip->irq_unmask = em_gio_irq_enable;
        irq_chip->irq_set_type = em_gio_irq_set_type;
@@ -342,14 +341,12 @@ static int em_gio_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
-       if (devm_request_irq(dev, irq[0]->start,
-                            em_gio_irq_handler, 0, name, p)) {
+       if (devm_request_irq(dev, irq[0], em_gio_irq_handler, 0, name, p)) {
                dev_err(dev, "failed to request low IRQ\n");
                return -ENOENT;
        }
 
-       if (devm_request_irq(dev, irq[1]->start,
-                            em_gio_irq_handler, 0, name, p)) {
+       if (devm_request_irq(dev, irq[1], em_gio_irq_handler, 0, name, p)) {
                dev_err(dev, "failed to request high IRQ\n");
                return -ENOENT;
        }
index cd07c948649feac6af3b9f6d0cffbb4aaf7ec0cb..f729e3e9e983786d42fa5b96e809587e032326d5 100644 (file)
@@ -386,7 +386,6 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
                if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio)))
                        return GPIO_LINE_DIRECTION_OUT;
 
-       /* This should not happen */
        return GPIO_LINE_DIRECTION_IN;
 }
 
index 47c172b2f5ad656c329ec6313cc00e2242b67b33..56d647a30e3eafee0178b6d416952e697635a745 100644 (file)
@@ -141,6 +141,61 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc,
        mutex_unlock(&chip->lock);
 }
 
+static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
+                                 unsigned int offset, int value)
+{
+       struct gpio_desc *desc;
+       struct gpio_chip *gc;
+       struct irq_sim *sim;
+       int curr, irq, irq_type;
+
+       gc = &chip->gc;
+       desc = &gc->gpiodev->descs[offset];
+       sim = &chip->irqsim;
+
+       mutex_lock(&chip->lock);
+
+       if (test_bit(FLAG_REQUESTED, &desc->flags) &&
+               !test_bit(FLAG_IS_OUT, &desc->flags)) {
+               curr = __gpio_mockup_get(chip, offset);
+               if (curr == value)
+                       goto out;
+
+               irq = irq_sim_irqnum(sim, offset);
+               irq_type = irq_get_trigger_type(irq);
+
+               if ((value == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) ||
+                       (value == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING)))
+                       irq_sim_fire(sim, offset);
+       }
+
+       /* Change the value unless we're actively driving the line. */
+       if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
+               !test_bit(FLAG_IS_OUT, &desc->flags))
+               __gpio_mockup_set(chip, offset, value);
+
+out:
+       chip->lines[offset].pull = value;
+       mutex_unlock(&chip->lock);
+       return 0;
+}
+
+static int gpio_mockup_set_config(struct gpio_chip *gc,
+                                 unsigned int offset, unsigned long config)
+{
+       struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
+
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_BIAS_PULL_UP:
+               return gpio_mockup_apply_pull(chip, offset, 1);
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               return gpio_mockup_apply_pull(chip, offset, 0);
+       default:
+               break;
+       }
+       return -ENOTSUPP;
+}
+
 static int gpio_mockup_dirout(struct gpio_chip *gc,
                              unsigned int offset, int value)
 {
@@ -221,12 +276,8 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file,
                                         size_t size, loff_t *ppos)
 {
        struct gpio_mockup_dbgfs_private *priv;
-       int rv, val, curr, irq, irq_type;
-       struct gpio_mockup_chip *chip;
+       int rv, val;
        struct seq_file *sfile;
-       struct gpio_desc *desc;
-       struct gpio_chip *gc;
-       struct irq_sim *sim;
 
        if (*ppos != 0)
                return -EINVAL;
@@ -239,35 +290,9 @@ static ssize_t gpio_mockup_debugfs_write(struct file *file,
 
        sfile = file->private_data;
        priv = sfile->private;
-       chip = priv->chip;
-       gc = &chip->gc;
-       desc = &gc->gpiodev->descs[priv->offset];
-       sim = &chip->irqsim;
-
-       mutex_lock(&chip->lock);
-
-       if (test_bit(FLAG_REQUESTED, &desc->flags) &&
-           !test_bit(FLAG_IS_OUT, &desc->flags)) {
-               curr = __gpio_mockup_get(chip, priv->offset);
-               if (curr == val)
-                       goto out;
-
-               irq = irq_sim_irqnum(sim, priv->offset);
-               irq_type = irq_get_trigger_type(irq);
-
-               if ((val == 1 && (irq_type & IRQ_TYPE_EDGE_RISING)) ||
-                   (val == 0 && (irq_type & IRQ_TYPE_EDGE_FALLING)))
-                       irq_sim_fire(sim, priv->offset);
-       }
-
-       /* Change the value unless we're actively driving the line. */
-       if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
-           !test_bit(FLAG_IS_OUT, &desc->flags))
-               __gpio_mockup_set(chip, priv->offset, val);
-
-out:
-       chip->lines[priv->offset].pull = val;
-       mutex_unlock(&chip->lock);
+       rv = gpio_mockup_apply_pull(priv->chip, priv->offset, val);
+       if (rv)
+               return rv;
 
        return size;
 }
@@ -413,6 +438,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
        gc->direction_output = gpio_mockup_dirout;
        gc->direction_input = gpio_mockup_dirin;
        gc->get_direction = gpio_mockup_get_direction;
+       gc->set_config = gpio_mockup_set_config;
        gc->to_irq = gpio_mockup_to_irq;
        gc->free = gpio_mockup_free;
 
index 9b2adf0ef88095fabd0ff041212efa2a7f6f341d..993bbeb3c0067f0f5c156ec5009d0799c36914e3 100644 (file)
@@ -776,23 +776,12 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
 {
        struct device *dev = &pdev->dev;
        struct mvebu_pwm *mvpwm;
-       struct resource *res;
        u32 set;
 
        if (!of_device_is_compatible(mvchip->chip.of_node,
                                     "marvell,armada-370-gpio"))
                return 0;
 
-       /*
-        * There are only two sets of PWM configuration registers for
-        * all the GPIO lines on those SoCs which this driver reserves
-        * for the first two GPIO chips. So if the resource is missing
-        * we can't treat it as an error.
-        */
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm");
-       if (!res)
-               return 0;
-
        if (IS_ERR(mvchip->clk))
                return PTR_ERR(mvchip->clk);
 
@@ -815,7 +804,13 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
        mvchip->mvpwm = mvpwm;
        mvpwm->mvchip = mvchip;
 
-       mvpwm->membase = devm_ioremap_resource(dev, res);
+       /*
+        * There are only two sets of PWM configuration registers for
+        * all the GPIO lines on those SoCs which this driver reserves
+        * for the first two GPIO chips. So if the resource is missing
+        * we can't treat it as an error.
+        */
+       mvpwm->membase = devm_platform_ioremap_resource_byname(pdev, "pwm");
        if (IS_ERR(mvpwm->membase))
                return PTR_ERR(mvpwm->membase);
 
index d7e6e68c25aff609a0c7cabe4b61b8334bf53446..f800b250971c7caca3dd8bc3cee5967319e6737d 100644 (file)
@@ -486,7 +486,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
        gpio_chip->ngpio = npins;
 
        irq_chip = &p->irq_chip;
-       irq_chip->name = name;
+       irq_chip->name = "gpio-rcar";
        irq_chip->parent_device = dev;
        irq_chip->irq_mask = gpio_rcar_irq_disable;
        irq_chip->irq_unmask = gpio_rcar_irq_enable;
index 57185b96c1105f163f805d32e65cbd46145db15a..55b43b7ce88db415552ced7731ab316671e66ff5 100644 (file)
 #include <dt-bindings/gpio/tegra186-gpio.h>
 #include <dt-bindings/gpio/tegra194-gpio.h>
 
+/* security registers */
+#define TEGRA186_GPIO_CTL_SCR 0x0c
+#define  TEGRA186_GPIO_CTL_SCR_SEC_WEN BIT(28)
+#define  TEGRA186_GPIO_CTL_SCR_SEC_REN BIT(27)
+
+#define TEGRA186_GPIO_INT_ROUTE_MAPPING(p, x) (0x14 + (p) * 0x20 + (x) * 4)
+
+/* control registers */
 #define TEGRA186_GPIO_ENABLE_CONFIG 0x00
 #define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
 #define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
@@ -24,6 +32,7 @@
 #define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2)
 #define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2)
 #define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE BIT(5)
 #define  TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
 
 #define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
@@ -44,9 +53,9 @@
 
 struct tegra_gpio_port {
        const char *name;
-       unsigned int offset;
+       unsigned int bank;
+       unsigned int port;
        unsigned int pins;
-       unsigned int irq;
 };
 
 struct tegra_gpio_soc {
@@ -64,6 +73,7 @@ struct tegra_gpio {
 
        const struct tegra_gpio_soc *soc;
 
+       void __iomem *secure;
        void __iomem *base;
 };
 
@@ -90,12 +100,15 @@ static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
                                            unsigned int pin)
 {
        const struct tegra_gpio_port *port;
+       unsigned int offset;
 
        port = tegra186_gpio_get_port(gpio, &pin);
        if (!port)
                return NULL;
 
-       return gpio->base + port->offset + pin * 0x20;
+       offset = port->bank * 0x1000 + port->port * 0x200;
+
+       return gpio->base + offset + pin * 0x20;
 }
 
 static int tegra186_gpio_get_direction(struct gpio_chip *chip,
@@ -205,6 +218,42 @@ static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
        writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE);
 }
 
+static int tegra186_gpio_set_config(struct gpio_chip *chip,
+                                   unsigned int offset,
+                                   unsigned long config)
+{
+       struct tegra_gpio *gpio = gpiochip_get_data(chip);
+       u32 debounce, value;
+       void __iomem *base;
+
+       base = tegra186_gpio_get_base(gpio, offset);
+       if (base == NULL)
+               return -ENXIO;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+
+       /*
+        * The Tegra186 GPIO controller supports a maximum of 255 ms debounce
+        * time.
+        */
+       if (debounce > 255000)
+               return -EINVAL;
+
+       debounce = DIV_ROUND_UP(debounce, USEC_PER_MSEC);
+
+       value = TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(debounce);
+       writel(value, base + TEGRA186_GPIO_DEBOUNCE_CONTROL);
+
+       value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+       value |= TEGRA186_GPIO_ENABLE_CONFIG_DEBOUNCE;
+       writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+       return 0;
+}
+
 static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
                                  const struct of_phandle_args *spec,
                                  u32 *flags)
@@ -343,12 +392,14 @@ static void tegra186_gpio_irq(struct irq_desc *desc)
 
        for (i = 0; i < gpio->soc->num_ports; i++) {
                const struct tegra_gpio_port *port = &gpio->soc->ports[i];
-               void __iomem *base = gpio->base + port->offset;
                unsigned int pin, irq;
                unsigned long value;
+               void __iomem *base;
 
-               /* skip ports that are not associated with this controller */
-               if (parent != gpio->irq[port->irq])
+               base = gpio->base + port->bank * 0x1000 + port->port * 0x200;
+
+               /* skip ports that are not associated with this bank */
+               if (parent != gpio->irq[port->bank])
                        goto skip;
 
                value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
@@ -444,13 +495,43 @@ static const struct of_device_id tegra186_pmc_of_match[] = {
        { /* sentinel */ }
 };
 
+static void tegra186_gpio_init_route_mapping(struct tegra_gpio *gpio)
+{
+       unsigned int i, j;
+       u32 value;
+
+       for (i = 0; i < gpio->soc->num_ports; i++) {
+               const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+               unsigned int offset, p = port->port;
+               void __iomem *base;
+
+               base = gpio->secure + port->bank * 0x1000 + 0x800;
+
+               value = readl(base + TEGRA186_GPIO_CTL_SCR);
+
+               /*
+                * For controllers that haven't been locked down yet, make
+                * sure to program the default interrupt route mapping.
+                */
+               if ((value & TEGRA186_GPIO_CTL_SCR_SEC_REN) == 0 &&
+                   (value & TEGRA186_GPIO_CTL_SCR_SEC_WEN) == 0) {
+                       for (j = 0; j < 8; j++) {
+                               offset = TEGRA186_GPIO_INT_ROUTE_MAPPING(p, j);
+
+                               value = readl(base + offset);
+                               value = BIT(port->pins) - 1;
+                               writel(value, base + offset);
+                       }
+               }
+       }
+}
+
 static int tegra186_gpio_probe(struct platform_device *pdev)
 {
        unsigned int i, j, offset;
        struct gpio_irq_chip *irq;
        struct tegra_gpio *gpio;
        struct device_node *np;
-       struct resource *res;
        char **names;
        int err;
 
@@ -460,8 +541,11 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
 
        gpio->soc = of_device_get_match_data(&pdev->dev);
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
-       gpio->base = devm_ioremap_resource(&pdev->dev, res);
+       gpio->secure = devm_platform_ioremap_resource_byname(pdev, "security");
+       if (IS_ERR(gpio->secure))
+               return PTR_ERR(gpio->secure);
+
+       gpio->base = devm_platform_ioremap_resource_byname(pdev, "gpio");
        if (IS_ERR(gpio->base))
                return PTR_ERR(gpio->base);
 
@@ -492,6 +576,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        gpio->gpio.direction_output = tegra186_gpio_direction_output;
        gpio->gpio.get = tegra186_gpio_get,
        gpio->gpio.set = tegra186_gpio_set;
+       gpio->gpio.set_config = tegra186_gpio_set_config;
 
        gpio->gpio.base = -1;
 
@@ -555,6 +640,8 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
                        return -EPROBE_DEFER;
        }
 
+       tegra186_gpio_init_route_mapping(gpio);
+
        irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
                                sizeof(*irq->map), GFP_KERNEL);
        if (!irq->map)
@@ -564,7 +651,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
                const struct tegra_gpio_port *port = &gpio->soc->ports[i];
 
                for (j = 0; j < port->pins; j++)
-                       irq->map[offset + j] = irq->parents[port->irq];
+                       irq->map[offset + j] = irq->parents[port->bank];
 
                offset += port->pins;
        }
@@ -583,38 +670,38 @@ static int tegra186_gpio_remove(struct platform_device *pdev)
        return 0;
 }
 
-#define TEGRA186_MAIN_GPIO_PORT(port, base, count, controller) \
-       [TEGRA186_MAIN_GPIO_PORT_##port] = {                    \
-               .name = #port,                                  \
-               .offset = base,                                 \
-               .pins = count,                                  \
-               .irq = controller,                              \
+#define TEGRA186_MAIN_GPIO_PORT(_name, _bank, _port, _pins)    \
+       [TEGRA186_MAIN_GPIO_PORT_##_name] = {                   \
+               .name = #_name,                                 \
+               .bank = _bank,                                  \
+               .port = _port,                                  \
+               .pins = _pins,                                  \
        }
 
 static const struct tegra_gpio_port tegra186_main_ports[] = {
-       TEGRA186_MAIN_GPIO_PORT( A, 0x2000, 7, 2),
-       TEGRA186_MAIN_GPIO_PORT( B, 0x3000, 7, 3),
-       TEGRA186_MAIN_GPIO_PORT( C, 0x3200, 7, 3),
-       TEGRA186_MAIN_GPIO_PORT( D, 0x3400, 6, 3),
-       TEGRA186_MAIN_GPIO_PORT( E, 0x2200, 8, 2),
-       TEGRA186_MAIN_GPIO_PORT( F, 0x2400, 6, 2),
-       TEGRA186_MAIN_GPIO_PORT( G, 0x4200, 6, 4),
-       TEGRA186_MAIN_GPIO_PORT( H, 0x1000, 7, 1),
-       TEGRA186_MAIN_GPIO_PORT( I, 0x0800, 8, 0),
-       TEGRA186_MAIN_GPIO_PORT( J, 0x5000, 8, 5),
-       TEGRA186_MAIN_GPIO_PORT( K, 0x5200, 1, 5),
-       TEGRA186_MAIN_GPIO_PORT( L, 0x1200, 8, 1),
-       TEGRA186_MAIN_GPIO_PORT( M, 0x5600, 6, 5),
-       TEGRA186_MAIN_GPIO_PORT( N, 0x0000, 7, 0),
-       TEGRA186_MAIN_GPIO_PORT( O, 0x0200, 4, 0),
-       TEGRA186_MAIN_GPIO_PORT( P, 0x4000, 7, 4),
-       TEGRA186_MAIN_GPIO_PORT( Q, 0x0400, 6, 0),
-       TEGRA186_MAIN_GPIO_PORT( R, 0x0a00, 6, 0),
-       TEGRA186_MAIN_GPIO_PORT( T, 0x0600, 4, 0),
-       TEGRA186_MAIN_GPIO_PORT( X, 0x1400, 8, 1),
-       TEGRA186_MAIN_GPIO_PORT( Y, 0x1600, 7, 1),
-       TEGRA186_MAIN_GPIO_PORT(BB, 0x2600, 2, 2),
-       TEGRA186_MAIN_GPIO_PORT(CC, 0x5400, 4, 5),
+       TEGRA186_MAIN_GPIO_PORT( A, 2, 0, 7),
+       TEGRA186_MAIN_GPIO_PORT( B, 3, 0, 7),
+       TEGRA186_MAIN_GPIO_PORT( C, 3, 1, 7),
+       TEGRA186_MAIN_GPIO_PORT( D, 3, 2, 6),
+       TEGRA186_MAIN_GPIO_PORT( E, 2, 1, 8),
+       TEGRA186_MAIN_GPIO_PORT( F, 2, 2, 6),
+       TEGRA186_MAIN_GPIO_PORT( G, 4, 1, 6),
+       TEGRA186_MAIN_GPIO_PORT( H, 1, 0, 7),
+       TEGRA186_MAIN_GPIO_PORT( I, 0, 4, 8),
+       TEGRA186_MAIN_GPIO_PORT( J, 5, 0, 8),
+       TEGRA186_MAIN_GPIO_PORT( K, 5, 1, 1),
+       TEGRA186_MAIN_GPIO_PORT( L, 1, 1, 8),
+       TEGRA186_MAIN_GPIO_PORT( M, 5, 3, 6),
+       TEGRA186_MAIN_GPIO_PORT( N, 0, 0, 7),
+       TEGRA186_MAIN_GPIO_PORT( O, 0, 1, 4),
+       TEGRA186_MAIN_GPIO_PORT( P, 4, 0, 7),
+       TEGRA186_MAIN_GPIO_PORT( Q, 0, 2, 6),
+       TEGRA186_MAIN_GPIO_PORT( R, 0, 5, 6),
+       TEGRA186_MAIN_GPIO_PORT( T, 0, 3, 4),
+       TEGRA186_MAIN_GPIO_PORT( X, 1, 2, 8),
+       TEGRA186_MAIN_GPIO_PORT( Y, 1, 3, 7),
+       TEGRA186_MAIN_GPIO_PORT(BB, 2, 3, 2),
+       TEGRA186_MAIN_GPIO_PORT(CC, 5, 2, 4),
 };
 
 static const struct tegra_gpio_soc tegra186_main_soc = {
@@ -624,23 +711,23 @@ static const struct tegra_gpio_soc tegra186_main_soc = {
        .instance = 0,
 };
 
-#define TEGRA186_AON_GPIO_PORT(port, base, count, controller)  \
-       [TEGRA186_AON_GPIO_PORT_##port] = {                     \
-               .name = #port,                                  \
-               .offset = base,                                 \
-               .pins = count,                                  \
-               .irq = controller,                              \
+#define TEGRA186_AON_GPIO_PORT(_name, _bank, _port, _pins)     \
+       [TEGRA186_AON_GPIO_PORT_##_name] = {                    \
+               .name = #_name,                                 \
+               .bank = _bank,                                  \
+               .port = _port,                                  \
+               .pins = _pins,                                  \
        }
 
 static const struct tegra_gpio_port tegra186_aon_ports[] = {
-       TEGRA186_AON_GPIO_PORT( S, 0x0200, 5, 0),
-       TEGRA186_AON_GPIO_PORT( U, 0x0400, 6, 0),
-       TEGRA186_AON_GPIO_PORT( V, 0x0800, 8, 0),
-       TEGRA186_AON_GPIO_PORT( W, 0x0a00, 8, 0),
-       TEGRA186_AON_GPIO_PORT( Z, 0x0e00, 4, 0),
-       TEGRA186_AON_GPIO_PORT(AA, 0x0c00, 8, 0),
-       TEGRA186_AON_GPIO_PORT(EE, 0x0600, 3, 0),
-       TEGRA186_AON_GPIO_PORT(FF, 0x0000, 5, 0),
+       TEGRA186_AON_GPIO_PORT( S, 0, 1, 5),
+       TEGRA186_AON_GPIO_PORT( U, 0, 2, 6),
+       TEGRA186_AON_GPIO_PORT( V, 0, 4, 8),
+       TEGRA186_AON_GPIO_PORT( W, 0, 5, 8),
+       TEGRA186_AON_GPIO_PORT( Z, 0, 7, 4),
+       TEGRA186_AON_GPIO_PORT(AA, 0, 6, 8),
+       TEGRA186_AON_GPIO_PORT(EE, 0, 3, 3),
+       TEGRA186_AON_GPIO_PORT(FF, 0, 0, 5),
 };
 
 static const struct tegra_gpio_soc tegra186_aon_soc = {
@@ -650,43 +737,43 @@ static const struct tegra_gpio_soc tegra186_aon_soc = {
        .instance = 1,
 };
 
-#define TEGRA194_MAIN_GPIO_PORT(port, base, count, controller) \
-       [TEGRA194_MAIN_GPIO_PORT_##port] = {                    \
-               .name = #port,                                  \
-               .offset = base,                                 \
-               .pins = count,                                  \
-               .irq = controller,                              \
+#define TEGRA194_MAIN_GPIO_PORT(_name, _bank, _port, _pins)    \
+       [TEGRA194_MAIN_GPIO_PORT_##_name] = {                   \
+               .name = #_name,                                 \
+               .bank = _bank,                                  \
+               .port = _port,                                  \
+               .pins = _pins,                                  \
        }
 
 static const struct tegra_gpio_port tegra194_main_ports[] = {
-       TEGRA194_MAIN_GPIO_PORT( A, 0x1400, 8, 1),
-       TEGRA194_MAIN_GPIO_PORT( B, 0x4e00, 2, 4),
-       TEGRA194_MAIN_GPIO_PORT( C, 0x4600, 8, 4),
-       TEGRA194_MAIN_GPIO_PORT( D, 0x4800, 4, 4),
-       TEGRA194_MAIN_GPIO_PORT( E, 0x4a00, 8, 4),
-       TEGRA194_MAIN_GPIO_PORT( F, 0x4c00, 6, 4),
-       TEGRA194_MAIN_GPIO_PORT( G, 0x4000, 8, 4),
-       TEGRA194_MAIN_GPIO_PORT( H, 0x4200, 8, 4),
-       TEGRA194_MAIN_GPIO_PORT( I, 0x4400, 5, 4),
-       TEGRA194_MAIN_GPIO_PORT( J, 0x5200, 6, 5),
-       TEGRA194_MAIN_GPIO_PORT( K, 0x3000, 8, 3),
-       TEGRA194_MAIN_GPIO_PORT( L, 0x3200, 4, 3),
-       TEGRA194_MAIN_GPIO_PORT( M, 0x2600, 8, 2),
-       TEGRA194_MAIN_GPIO_PORT( N, 0x2800, 3, 2),
-       TEGRA194_MAIN_GPIO_PORT( O, 0x5000, 6, 5),
-       TEGRA194_MAIN_GPIO_PORT( P, 0x2a00, 8, 2),
-       TEGRA194_MAIN_GPIO_PORT( Q, 0x2c00, 8, 2),
-       TEGRA194_MAIN_GPIO_PORT( R, 0x2e00, 6, 2),
-       TEGRA194_MAIN_GPIO_PORT( S, 0x3600, 8, 3),
-       TEGRA194_MAIN_GPIO_PORT( T, 0x3800, 8, 3),
-       TEGRA194_MAIN_GPIO_PORT( U, 0x3a00, 1, 3),
-       TEGRA194_MAIN_GPIO_PORT( V, 0x1000, 8, 1),
-       TEGRA194_MAIN_GPIO_PORT( W, 0x1200, 2, 1),
-       TEGRA194_MAIN_GPIO_PORT( X, 0x2000, 8, 2),
-       TEGRA194_MAIN_GPIO_PORT( Y, 0x2200, 8, 2),
-       TEGRA194_MAIN_GPIO_PORT( Z, 0x2400, 8, 2),
-       TEGRA194_MAIN_GPIO_PORT(FF, 0x3400, 2, 3),
-       TEGRA194_MAIN_GPIO_PORT(GG, 0x0000, 2, 0)
+       TEGRA194_MAIN_GPIO_PORT( A, 1, 2, 8),
+       TEGRA194_MAIN_GPIO_PORT( B, 4, 7, 2),
+       TEGRA194_MAIN_GPIO_PORT( C, 4, 3, 8),
+       TEGRA194_MAIN_GPIO_PORT( D, 4, 4, 4),
+       TEGRA194_MAIN_GPIO_PORT( E, 4, 5, 8),
+       TEGRA194_MAIN_GPIO_PORT( F, 4, 6, 6),
+       TEGRA194_MAIN_GPIO_PORT( G, 4, 0, 8),
+       TEGRA194_MAIN_GPIO_PORT( H, 4, 1, 8),
+       TEGRA194_MAIN_GPIO_PORT( I, 4, 2, 5),
+       TEGRA194_MAIN_GPIO_PORT( J, 5, 1, 6),
+       TEGRA194_MAIN_GPIO_PORT( K, 3, 0, 8),
+       TEGRA194_MAIN_GPIO_PORT( L, 3, 1, 4),
+       TEGRA194_MAIN_GPIO_PORT( M, 2, 3, 8),
+       TEGRA194_MAIN_GPIO_PORT( N, 2, 4, 3),
+       TEGRA194_MAIN_GPIO_PORT( O, 5, 0, 6),
+       TEGRA194_MAIN_GPIO_PORT( P, 2, 5, 8),
+       TEGRA194_MAIN_GPIO_PORT( Q, 2, 6, 8),
+       TEGRA194_MAIN_GPIO_PORT( R, 2, 7, 6),
+       TEGRA194_MAIN_GPIO_PORT( S, 3, 3, 8),
+       TEGRA194_MAIN_GPIO_PORT( T, 3, 4, 8),
+       TEGRA194_MAIN_GPIO_PORT( U, 3, 5, 1),
+       TEGRA194_MAIN_GPIO_PORT( V, 1, 0, 8),
+       TEGRA194_MAIN_GPIO_PORT( W, 1, 1, 2),
+       TEGRA194_MAIN_GPIO_PORT( X, 2, 0, 8),
+       TEGRA194_MAIN_GPIO_PORT( Y, 2, 1, 8),
+       TEGRA194_MAIN_GPIO_PORT( Z, 2, 2, 8),
+       TEGRA194_MAIN_GPIO_PORT(FF, 3, 2, 2),
+       TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2)
 };
 
 static const struct tegra_gpio_soc tegra194_main_soc = {
@@ -696,20 +783,20 @@ static const struct tegra_gpio_soc tegra194_main_soc = {
        .instance = 0,
 };
 
-#define TEGRA194_AON_GPIO_PORT(port, base, count, controller)  \
-       [TEGRA194_AON_GPIO_PORT_##port] = {                     \
-               .name = #port,                                  \
-               .offset = base,                                 \
-               .pins = count,                                  \
-               .irq = controller,                              \
+#define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins)     \
+       [TEGRA194_AON_GPIO_PORT_##_name] = {                    \
+               .name = #_name,                                 \
+               .bank = _bank,                                  \
+               .port = _port,                                  \
+               .pins = _pins,                                  \
        }
 
 static const struct tegra_gpio_port tegra194_aon_ports[] = {
-       TEGRA194_AON_GPIO_PORT(AA, 0x0600, 8, 0),
-       TEGRA194_AON_GPIO_PORT(BB, 0x0800, 4, 0),
-       TEGRA194_AON_GPIO_PORT(CC, 0x0200, 8, 0),
-       TEGRA194_AON_GPIO_PORT(DD, 0x0400, 3, 0),
-       TEGRA194_AON_GPIO_PORT(EE, 0x0000, 7, 0)
+       TEGRA194_AON_GPIO_PORT(AA, 0, 3, 8),
+       TEGRA194_AON_GPIO_PORT(BB, 0, 4, 4),
+       TEGRA194_AON_GPIO_PORT(CC, 0, 1, 8),
+       TEGRA194_AON_GPIO_PORT(DD, 0, 2, 3),
+       TEGRA194_AON_GPIO_PORT(EE, 0, 0, 7)
 };
 
 static const struct tegra_gpio_soc tegra194_aon_soc = {
index bb183f584d92f6e2e0b366c4b01a690dcc776ebc..773e5c24309e49b3f989a453df40373311afc15b 100644 (file)
@@ -308,7 +308,6 @@ MODULE_DEVICE_TABLE(of, bcm_iproc_gpio_of_match);
 static struct platform_driver bcm_iproc_gpio_driver = {
        .driver = {
                .name = "iproc-xgs-gpio",
-               .owner = THIS_MODULE,
                .of_match_table = bcm_iproc_gpio_of_match,
        },
        .probe = iproc_gpio_probe,
index 1dc144f834832f324a806220857c9a3d41437d5a..8fdde922786bdcfdc6283f514d8928bc1ac7df62 100644 (file)
@@ -430,9 +430,127 @@ struct linehandle_state {
        (GPIOHANDLE_REQUEST_INPUT | \
        GPIOHANDLE_REQUEST_OUTPUT | \
        GPIOHANDLE_REQUEST_ACTIVE_LOW | \
+       GPIOHANDLE_REQUEST_BIAS_PULL_UP | \
+       GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \
+       GPIOHANDLE_REQUEST_BIAS_DISABLE | \
        GPIOHANDLE_REQUEST_OPEN_DRAIN | \
        GPIOHANDLE_REQUEST_OPEN_SOURCE)
 
+static int linehandle_validate_flags(u32 flags)
+{
+       /* Return an error if an unknown flag is set */
+       if (flags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
+               return -EINVAL;
+
+       /*
+        * Do not allow both INPUT & OUTPUT flags to be set as they are
+        * contradictory.
+        */
+       if ((flags & GPIOHANDLE_REQUEST_INPUT) &&
+           (flags & GPIOHANDLE_REQUEST_OUTPUT))
+               return -EINVAL;
+
+       /*
+        * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
+        * the hardware actually supports enabling both at the same time the
+        * electrical result would be disastrous.
+        */
+       if ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) &&
+           (flags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
+               return -EINVAL;
+
+       /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
+       if (!(flags & GPIOHANDLE_REQUEST_OUTPUT) &&
+           ((flags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
+            (flags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
+               return -EINVAL;
+
+       /* Bias flags only allowed for input or output mode. */
+       if (!((flags & GPIOHANDLE_REQUEST_INPUT) ||
+             (flags & GPIOHANDLE_REQUEST_OUTPUT)) &&
+           ((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) ||
+            (flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) ||
+            (flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)))
+               return -EINVAL;
+
+       /* Only one bias flag can be set. */
+       if (((flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
+            (flags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
+                       GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
+           ((flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
+            (flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void linehandle_configure_flag(unsigned long *flagsp,
+                                     u32 bit, bool active)
+{
+       if (active)
+               set_bit(bit, flagsp);
+       else
+               clear_bit(bit, flagsp);
+}
+
+static long linehandle_set_config(struct linehandle_state *lh,
+                                 void __user *ip)
+{
+       struct gpiohandle_config gcnf;
+       struct gpio_desc *desc;
+       int i, ret;
+       u32 lflags;
+       unsigned long *flagsp;
+
+       if (copy_from_user(&gcnf, ip, sizeof(gcnf)))
+               return -EFAULT;
+
+       lflags = gcnf.flags;
+       ret = linehandle_validate_flags(lflags);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < lh->numdescs; i++) {
+               desc = lh->descs[i];
+               flagsp = &desc->flags;
+
+               linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW,
+                       lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW);
+
+               linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN,
+                       lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN);
+
+               linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE,
+                       lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE);
+
+               linehandle_configure_flag(flagsp, FLAG_PULL_UP,
+                       lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP);
+
+               linehandle_configure_flag(flagsp, FLAG_PULL_DOWN,
+                       lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN);
+
+               linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE,
+                       lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE);
+
+               /*
+                * Lines have to be requested explicitly for input
+                * or output, else the line will be treated "as is".
+                */
+               if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
+                       int val = !!gcnf.default_values[i];
+
+                       ret = gpiod_direction_output(desc, val);
+                       if (ret)
+                               return ret;
+               } else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
+                       ret = gpiod_direction_input(desc);
+                       if (ret)
+                               return ret;
+               }
+       }
+       return 0;
+}
+
 static long linehandle_ioctl(struct file *filep, unsigned int cmd,
                             unsigned long arg)
 {
@@ -483,6 +601,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
                                              lh->descs,
                                              NULL,
                                              vals);
+       } else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) {
+               return linehandle_set_config(lh, ip);
        }
        return -EINVAL;
 }
@@ -534,32 +654,9 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
 
        lflags = handlereq.flags;
 
-       /* Return an error if an unknown flag is set */
-       if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS)
-               return -EINVAL;
-
-       /*
-        * Do not allow both INPUT & OUTPUT flags to be set as they are
-        * contradictory.
-        */
-       if ((lflags & GPIOHANDLE_REQUEST_INPUT) &&
-           (lflags & GPIOHANDLE_REQUEST_OUTPUT))
-               return -EINVAL;
-
-       /*
-        * Do not allow OPEN_SOURCE & OPEN_DRAIN flags in a single request. If
-        * the hardware actually supports enabling both at the same time the
-        * electrical result would be disastrous.
-        */
-       if ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) &&
-           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
-               return -EINVAL;
-
-       /* OPEN_DRAIN and OPEN_SOURCE flags only make sense for output mode. */
-       if (!(lflags & GPIOHANDLE_REQUEST_OUTPUT) &&
-           ((lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
-            (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
-               return -EINVAL;
+       ret = linehandle_validate_flags(lflags);
+       if (ret)
+               return ret;
 
        lh = kzalloc(sizeof(*lh), GFP_KERNEL);
        if (!lh)
@@ -601,6 +698,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
                        set_bit(FLAG_OPEN_DRAIN, &desc->flags);
                if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
                        set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE)
+                       set_bit(FLAG_BIAS_DISABLE, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)
+                       set_bit(FLAG_PULL_DOWN, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
+                       set_bit(FLAG_PULL_UP, &desc->flags);
 
                ret = gpiod_set_transitory(desc, false);
                if (ret < 0)
@@ -921,6 +1024,14 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
            (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
                return -EINVAL;
 
+       /* Only one bias flag can be set. */
+       if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) &&
+            (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN |
+                       GPIOHANDLE_REQUEST_BIAS_PULL_UP))) ||
+           ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) &&
+            (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)))
+               return -EINVAL;
+
        le = kzalloc(sizeof(*le), GFP_KERNEL);
        if (!le)
                return -ENOMEM;
@@ -947,6 +1058,12 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
 
        if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW)
                set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+       if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE)
+               set_bit(FLAG_BIAS_DISABLE, &desc->flags);
+       if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)
+               set_bit(FLAG_PULL_DOWN, &desc->flags);
+       if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
+               set_bit(FLAG_PULL_UP, &desc->flags);
 
        ret = gpiod_direction_input(desc);
        if (ret)
@@ -1100,6 +1217,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
                        lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
                                           GPIOLINE_FLAG_IS_OUT);
+               if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE;
+               if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
+               if (test_bit(FLAG_PULL_UP, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
 
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
@@ -2797,6 +2920,9 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
                clear_bit(FLAG_REQUESTED, &desc->flags);
                clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
                clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               clear_bit(FLAG_PULL_UP, &desc->flags);
+               clear_bit(FLAG_PULL_DOWN, &desc->flags);
+               clear_bit(FLAG_BIAS_DISABLE, &desc->flags);
                clear_bit(FLAG_IS_HOGGED, &desc->flags);
                ret = true;
        }
@@ -2923,6 +3049,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
        unsigned arg;
 
        switch (mode) {
+       case PIN_CONFIG_BIAS_DISABLE:
        case PIN_CONFIG_BIAS_PULL_DOWN:
        case PIN_CONFIG_BIAS_PULL_UP:
                arg = 1;
@@ -2936,6 +3063,26 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
        return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
 }
 
+static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc)
+{
+       int bias = 0;
+       int ret = 0;
+
+       if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
+               bias = PIN_CONFIG_BIAS_DISABLE;
+       else if (test_bit(FLAG_PULL_UP, &desc->flags))
+               bias = PIN_CONFIG_BIAS_PULL_UP;
+       else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+               bias = PIN_CONFIG_BIAS_PULL_DOWN;
+
+       if (bias) {
+               ret = gpio_set_config(chip, gpio_chip_hwgpio(desc), bias);
+               if (ret != -ENOTSUPP)
+                       return ret;
+       }
+       return 0;
+}
+
 /**
  * gpiod_direction_input - set the GPIO direction to input
  * @desc:      GPIO to set to input
@@ -2980,15 +3127,10 @@ int gpiod_direction_input(struct gpio_desc *desc)
                           __func__);
                return -EIO;
        }
-       if (ret == 0)
+       if (ret == 0) {
                clear_bit(FLAG_IS_OUT, &desc->flags);
-
-       if (test_bit(FLAG_PULL_UP, &desc->flags))
-               gpio_set_config(chip, gpio_chip_hwgpio(desc),
-                               PIN_CONFIG_BIAS_PULL_UP);
-       else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
-               gpio_set_config(chip, gpio_chip_hwgpio(desc),
-                               PIN_CONFIG_BIAS_PULL_DOWN);
+               ret = gpio_set_bias(chip, desc);
+       }
 
        trace_gpio_direction(desc_to_gpio(desc), 1, ret);
 
@@ -3118,6 +3260,9 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
        }
 
 set_output_value:
+       ret = gpio_set_bias(gc, desc);
+       if (ret)
+               return ret;
        return gpiod_direction_output_raw_commit(desc, value);
 
 set_output_flag:
index b8b10a409c7b9c6584e6e176d9246aec5c394258..ca9bc1e4803c2979c3ea3d68b1ce893b2d154ce5 100644 (file)
@@ -110,6 +110,7 @@ struct gpio_desc {
 #define FLAG_TRANSITORY 12     /* GPIO may lose value in sleep or reset */
 #define FLAG_PULL_UP    13     /* GPIO has pull up enabled */
 #define FLAG_PULL_DOWN  14     /* GPIO has pull down enabled */
+#define FLAG_BIAS_DISABLE    15        /* GPIO has pull disabled */
 
        /* Connection label */
        const char              *label;
index 61cc2354ef1bfe7eb09a6d93b9d7c22b3ed4c713..d9c9c9ebad2b1bd03f1328ceb2ab2bdc354a7cb1 100644 (file)
@@ -284,8 +284,8 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi)
        else
                dvi->connector_type = DRM_MODE_CONNECTOR_DVID;
 
-       dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode,
-                                       "hpd-gpios", 0, GPIOD_IN, "hpd");
+       dvi->hpd = fwnode_gpiod_get_index(&connector_node->fwnode,
+                                         "hpd", 0, GPIOD_IN, "hpd");
        if (IS_ERR(dvi->hpd)) {
                ret = PTR_ERR(dvi->hpd);
                dvi->hpd = NULL;
index 831539419c3016e11ae1da143d344a7ea5b1c1bf..059db06104450504c7c283ccec1b908a5454644f 100644 (file)
@@ -5710,11 +5710,10 @@ static int mlx5_ib_rn_get_params(struct ib_device *device, u8 port_num,
 
 static void delay_drop_debugfs_cleanup(struct mlx5_ib_dev *dev)
 {
-       if (!dev->delay_drop.dbg)
+       if (!dev->delay_drop.dir_debugfs)
                return;
-       debugfs_remove_recursive(dev->delay_drop.dbg->dir_debugfs);
-       kfree(dev->delay_drop.dbg);
-       dev->delay_drop.dbg = NULL;
+       debugfs_remove_recursive(dev->delay_drop.dir_debugfs);
+       dev->delay_drop.dir_debugfs = NULL;
 }
 
 static void cancel_delay_drop(struct mlx5_ib_dev *dev)
@@ -5765,52 +5764,22 @@ static const struct file_operations fops_delay_drop_timeout = {
        .read   = delay_drop_timeout_read,
 };
 
-static int delay_drop_debugfs_init(struct mlx5_ib_dev *dev)
+static void delay_drop_debugfs_init(struct mlx5_ib_dev *dev)
 {
-       struct mlx5_ib_dbg_delay_drop *dbg;
+       struct dentry *root;
 
        if (!mlx5_debugfs_root)
-               return 0;
-
-       dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
-       if (!dbg)
-               return -ENOMEM;
-
-       dev->delay_drop.dbg = dbg;
-
-       dbg->dir_debugfs =
-               debugfs_create_dir("delay_drop",
-                                  dev->mdev->priv.dbg_root);
-       if (!dbg->dir_debugfs)
-               goto out_debugfs;
-
-       dbg->events_cnt_debugfs =
-               debugfs_create_atomic_t("num_timeout_events", 0400,
-                                       dbg->dir_debugfs,
-                                       &dev->delay_drop.events_cnt);
-       if (!dbg->events_cnt_debugfs)
-               goto out_debugfs;
-
-       dbg->rqs_cnt_debugfs =
-               debugfs_create_atomic_t("num_rqs", 0400,
-                                       dbg->dir_debugfs,
-                                       &dev->delay_drop.rqs_cnt);
-       if (!dbg->rqs_cnt_debugfs)
-               goto out_debugfs;
-
-       dbg->timeout_debugfs =
-               debugfs_create_file("timeout", 0600,
-                                   dbg->dir_debugfs,
-                                   &dev->delay_drop,
-                                   &fops_delay_drop_timeout);
-       if (!dbg->timeout_debugfs)
-               goto out_debugfs;
+               return;
 
-       return 0;
+       root = debugfs_create_dir("delay_drop", dev->mdev->priv.dbg_root);
+       dev->delay_drop.dir_debugfs = root;
 
-out_debugfs:
-       delay_drop_debugfs_cleanup(dev);
-       return -ENOMEM;
+       debugfs_create_atomic_t("num_timeout_events", 0400, root,
+                               &dev->delay_drop.events_cnt);
+       debugfs_create_atomic_t("num_rqs", 0400, root,
+                               &dev->delay_drop.rqs_cnt);
+       debugfs_create_file("timeout", 0600, root, &dev->delay_drop,
+                           &fops_delay_drop_timeout);
 }
 
 static void init_delay_drop(struct mlx5_ib_dev *dev)
@@ -5826,8 +5795,7 @@ static void init_delay_drop(struct mlx5_ib_dev *dev)
        atomic_set(&dev->delay_drop.rqs_cnt, 0);
        atomic_set(&dev->delay_drop.events_cnt, 0);
 
-       if (delay_drop_debugfs_init(dev))
-               mlx5_ib_warn(dev, "Failed to init delay drop debugfs\n");
+       delay_drop_debugfs_init(dev);
 }
 
 static void mlx5_ib_unbind_slave_port(struct mlx5_ib_dev *ibdev,
index 1a98ee2e01c4b991b10b3c83f8395cf79de94524..55ce599db803dcdc77058db5d82f85e6d3a10614 100644 (file)
@@ -792,13 +792,6 @@ enum {
        MLX5_MAX_DELAY_DROP_TIMEOUT_MS = 100,
 };
 
-struct mlx5_ib_dbg_delay_drop {
-       struct dentry           *dir_debugfs;
-       struct dentry           *rqs_cnt_debugfs;
-       struct dentry           *events_cnt_debugfs;
-       struct dentry           *timeout_debugfs;
-};
-
 struct mlx5_ib_delay_drop {
        struct mlx5_ib_dev     *dev;
        struct work_struct      delay_drop_work;
@@ -808,7 +801,7 @@ struct mlx5_ib_delay_drop {
        bool                    activate;
        atomic_t                events_cnt;
        atomic_t                rqs_cnt;
-       struct mlx5_ib_dbg_delay_drop *dbg;
+       struct dentry           *dir_debugfs;
 };
 
 enum mlx5_ib_stages {
index 8f0ddcbeed9df6ef79198ada0a869543e836042f..301fa10f419b6a7c9a1b50d759fd0fbbfc0f7692 100644 (file)
@@ -225,36 +225,16 @@ static const struct debugfs_reg32 fei_sys_regs[] = {
 
 void c8sectpfe_debugfs_init(struct c8sectpfei *fei)
 {
-       struct dentry           *root;
-       struct dentry           *file;
-
-       root = debugfs_create_dir("c8sectpfe", NULL);
-       if (!root)
-               goto err;
-
-       fei->root = root;
-
        fei->regset =  devm_kzalloc(fei->dev, sizeof(*fei->regset), GFP_KERNEL);
        if (!fei->regset)
-               goto err;
+               return;
 
        fei->regset->regs = fei_sys_regs;
        fei->regset->nregs = ARRAY_SIZE(fei_sys_regs);
        fei->regset->base = fei->io;
 
-       file = debugfs_create_regset32("registers", S_IRUGO, root,
-                               fei->regset);
-       if (!file) {
-               dev_err(fei->dev,
-                       "%s not able to create 'registers' debugfs\n"
-                       , __func__);
-               goto err;
-       }
-
-       return;
-
-err:
-       debugfs_remove_recursive(root);
+       fei->root = debugfs_create_dir("c8sectpfe", NULL);
+       debugfs_create_regset32("registers", S_IRUGO, fei->root, fei->regset);
 }
 
 void c8sectpfe_debugfs_exit(struct c8sectpfei *fei)
index f30448bf3a6316b4cace786477a04aea54c302de..6c1a23cb3e8c0fa8ef1f5bf8b871a10c763fa894 100644 (file)
@@ -340,8 +340,6 @@ static const struct of_device_id sram_dt_ids[] = {
 static int sram_probe(struct platform_device *pdev)
 {
        struct sram_dev *sram;
-       struct resource *res;
-       size_t size;
        int ret;
        int (*init_func)(void);
 
@@ -351,25 +349,14 @@ static int sram_probe(struct platform_device *pdev)
 
        sram->dev = &pdev->dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(sram->dev, "found no memory resource\n");
-               return -EINVAL;
-       }
-
-       size = resource_size(res);
-
-       if (!devm_request_mem_region(sram->dev, res->start, size, pdev->name)) {
-               dev_err(sram->dev, "could not request region for resource\n");
-               return -EBUSY;
-       }
-
        if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc"))
-               sram->virt_base = devm_ioremap(sram->dev, res->start, size);
+               sram->virt_base = devm_platform_ioremap_resource(pdev, 0);
        else
-               sram->virt_base = devm_ioremap_wc(sram->dev, res->start, size);
-       if (!sram->virt_base)
-               return -ENOMEM;
+               sram->virt_base = devm_platform_ioremap_resource_wc(pdev, 0);
+       if (IS_ERR(sram->virt_base)) {
+               dev_err(&pdev->dev, "could not map SRAM registers\n");
+               return PTR_ERR(sram->virt_base);
+       }
 
        sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
                                          NUMA_NO_NODE, NULL);
@@ -382,7 +369,8 @@ static int sram_probe(struct platform_device *pdev)
        else
                clk_prepare_enable(sram->clk);
 
-       ret = sram_reserve_regions(sram, res);
+       ret = sram_reserve_regions(sram,
+                       platform_get_resource(pdev, IORESOURCE_MEM, 0));
        if (ret)
                goto err_disable_clk;
 
index c26fbe5f22221d955bc4fadf1a06377359a06f95..34c992d87529893261e128d4c659e1b0b5df82fc 100644 (file)
@@ -583,11 +583,11 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
 
        debugfs_create_file("regs", S_IRUSR, root, host, &atmci_regs_fops);
        debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
-       debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
-       debugfs_create_x32("pending_events", S_IRUSR, root,
-                          (u32 *)&host->pending_events);
-       debugfs_create_x32("completed_events", S_IRUSR, root,
-                          (u32 *)&host->completed_events);
+       debugfs_create_u32("state", S_IRUSR, root, &host->state);
+       debugfs_create_xul("pending_events", S_IRUSR, root,
+                          &host->pending_events);
+       debugfs_create_xul("completed_events", S_IRUSR, root,
+                          &host->completed_events);
 }
 
 #if defined(CONFIG_OF)
index 79c55c7b4afd92313b8f818690d9654998613f59..709de34beca8888ae72492c68a33d14002c3b2a5 100644 (file)
@@ -176,11 +176,11 @@ static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
 
        debugfs_create_file("regs", S_IRUSR, root, host, &dw_mci_regs_fops);
        debugfs_create_file("req", S_IRUSR, root, slot, &dw_mci_req_fops);
-       debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
-       debugfs_create_x32("pending_events", S_IRUSR, root,
-                          (u32 *)&host->pending_events);
-       debugfs_create_x32("completed_events", S_IRUSR, root,
-                          (u32 *)&host->completed_events);
+       debugfs_create_u32("state", S_IRUSR, root, &host->state);
+       debugfs_create_xul("pending_events", S_IRUSR, root,
+                          &host->pending_events);
+       debugfs_create_xul("completed_events", S_IRUSR, root,
+                          &host->completed_events);
 }
 #endif /* defined(CONFIG_DEBUG_FS) */
 
index 40b079162804fb0c7d43d000392abb5c60448c37..bd40b114d6cd72143aa11fd557259854ceb412ce 100644 (file)
@@ -102,8 +102,8 @@ static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
        debugfs_create_blob("last_rx_msg", 0400, ser->debugfs_tty_dir,
                            &ser->rx_blob);
 
-       debugfs_create_x32("ser_state", 0400, ser->debugfs_tty_dir,
-                          (u32 *)&ser->state);
+       debugfs_create_xul("ser_state", 0400, ser->debugfs_tty_dir,
+                          &ser->state);
 
        debugfs_create_x8("tty_status", 0400, ser->debugfs_tty_dir,
                          &ser->tty_status);
index 65865e460ab87eb4847db95a3600007c88cf19a4..04dd46647db361c35a2a01c41a480a5165b231b2 100644 (file)
@@ -354,13 +354,10 @@ static void pp_clear_ctx(struct pp_ctx *pp)
 static void pp_setup_dbgfs(struct pp_ctx *pp)
 {
        struct pci_dev *pdev = pp->ntb->pdev;
-       void *ret;
 
        pp->dbgfs_dir = debugfs_create_dir(pci_name(pdev), pp_dbgfs_topdir);
 
-       ret = debugfs_create_atomic_t("count", 0600, pp->dbgfs_dir, &pp->count);
-       if (!ret)
-               dev_warn(&pp->ntb->dev, "DebugFS unsupported\n");
+       debugfs_create_atomic_t("count", 0600, pp->dbgfs_dir, &pp->count);
 }
 
 static void pp_clear_dbgfs(struct pp_ctx *pp)
index b47a2292fe8e8904a653ad295404c8d56282c9df..d93891a05f6033638916d7eda0a560110dcaf4ef 100644 (file)
@@ -480,6 +480,7 @@ int of_platform_populate(struct device_node *root,
        pr_debug("%s()\n", __func__);
        pr_debug(" starting at: %pOF\n", root);
 
+       device_links_supplier_sync_state_pause();
        for_each_child_of_node(root, child) {
                rc = of_platform_bus_create(child, matches, lookup, parent, true);
                if (rc) {
@@ -487,6 +488,8 @@ int of_platform_populate(struct device_node *root,
                        break;
                }
        }
+       device_links_supplier_sync_state_resume();
+
        of_node_set_flag(root, OF_POPULATED_BUS);
 
        of_node_put(root);
@@ -518,6 +521,7 @@ static int __init of_platform_default_populate_init(void)
        if (!of_have_populated_dt())
                return -ENODEV;
 
+       device_links_supplier_sync_state_pause();
        /*
         * Handle certain compatibles explicitly, since we don't want to create
         * platform_devices for every node in /reserved-memory with a
@@ -538,6 +542,14 @@ static int __init of_platform_default_populate_init(void)
        return 0;
 }
 arch_initcall_sync(of_platform_default_populate_init);
+
+static int __init of_platform_sync_state_init(void)
+{
+       if (of_have_populated_dt())
+               device_links_supplier_sync_state_resume();
+       return 0;
+}
+late_initcall_sync(of_platform_sync_state_init);
 #endif
 
 int of_platform_device_destroy(struct device *dev, void *data)
index d7fa75e31f22415c447f05fa99437e1591cb0a1a..0fa04692e3ccf698bc5aadf4471f5edffceded21 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/string.h>
+#include <linux/moduleparam.h>
 
 #include "of_private.h"
 
@@ -985,6 +986,302 @@ of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
        return of_device_get_match_data(dev);
 }
 
+static bool of_is_ancestor_of(struct device_node *test_ancestor,
+                             struct device_node *child)
+{
+       of_node_get(child);
+       while (child) {
+               if (child == test_ancestor) {
+                       of_node_put(child);
+                       return false;
+               }
+               child = of_get_next_parent(child);
+       }
+       return true;
+}
+
+/**
+ * of_link_to_phandle - Add device link to supplier from supplier phandle
+ * @dev: consumer device
+ * @sup_np: phandle to supplier device tree node
+ *
+ * Given a phandle to a supplier device tree node (@sup_np), this function
+ * finds the device that owns the supplier device tree node and creates a
+ * device link from @dev consumer device to the supplier device. This function
+ * doesn't create device links for invalid scenarios such as trying to create a
+ * link with a parent device as the consumer of its child device. In such
+ * cases, it returns an error.
+ *
+ * Returns:
+ * - 0 if link successfully created to supplier
+ * - -EAGAIN if linking to the supplier should be reattempted
+ * - -EINVAL if the supplier link is invalid and should not be created
+ * - -ENODEV if there is no device that corresponds to the supplier phandle
+ */
+static int of_link_to_phandle(struct device *dev, struct device_node *sup_np,
+                             u32 dl_flags)
+{
+       struct device *sup_dev;
+       int ret = 0;
+       struct device_node *tmp_np = sup_np;
+       int is_populated;
+
+       of_node_get(sup_np);
+       /*
+        * Find the device node that contains the supplier phandle.  It may be
+        * @sup_np or it may be an ancestor of @sup_np.
+        */
+       while (sup_np && !of_find_property(sup_np, "compatible", NULL))
+               sup_np = of_get_next_parent(sup_np);
+       if (!sup_np) {
+               dev_dbg(dev, "Not linking to %pOFP - No device\n", tmp_np);
+               return -ENODEV;
+       }
+
+       /*
+        * Don't allow linking a device node as a consumer of one of its
+        * descendant nodes. By definition, a child node can't be a functional
+        * dependency for the parent node.
+        */
+       if (!of_is_ancestor_of(dev->of_node, sup_np)) {
+               dev_dbg(dev, "Not linking to %pOFP - is descendant\n", sup_np);
+               of_node_put(sup_np);
+               return -EINVAL;
+       }
+       sup_dev = get_dev_from_fwnode(&sup_np->fwnode);
+       is_populated = of_node_check_flag(sup_np, OF_POPULATED);
+       of_node_put(sup_np);
+       if (!sup_dev && is_populated) {
+               /* Early device without struct device. */
+               dev_dbg(dev, "Not linking to %pOFP - No struct device\n",
+                       sup_np);
+               return -ENODEV;
+       } else if (!sup_dev) {
+               return -EAGAIN;
+       }
+       if (!device_link_add(dev, sup_dev, dl_flags))
+               ret = -EAGAIN;
+       put_device(sup_dev);
+       return ret;
+}
+
+/**
+ * parse_prop_cells - Property parsing function for suppliers
+ *
+ * @np:                Pointer to device tree node containing a list
+ * @prop_name: Name of property to be parsed. Expected to hold phandle values
+ * @index:     For properties holding a list of phandles, this is the index
+ *             into the list.
+ * @list_name: Property name that is known to contain list of phandle(s) to
+ *             supplier(s)
+ * @cells_name:        property name that specifies phandles' arguments count
+ *
+ * This is a helper function to parse properties that have a known fixed name
+ * and are a list of phandles and phandle arguments.
+ *
+ * Returns:
+ * - phandle node pointer with refcount incremented. Caller must of_node_put()
+ *   on it when done.
+ * - NULL if no phandle found at index
+ */
+static struct device_node *parse_prop_cells(struct device_node *np,
+                                           const char *prop_name, int index,
+                                           const char *list_name,
+                                           const char *cells_name)
+{
+       struct of_phandle_args sup_args;
+
+       if (strcmp(prop_name, list_name))
+               return NULL;
+
+       if (of_parse_phandle_with_args(np, list_name, cells_name, index,
+                                      &sup_args))
+               return NULL;
+
+       return sup_args.np;
+}
+
+#define DEFINE_SIMPLE_PROP(fname, name, cells)                           \
+static struct device_node *parse_##fname(struct device_node *np,         \
+                                       const char *prop_name, int index) \
+{                                                                        \
+       return parse_prop_cells(np, prop_name, index, name, cells);       \
+}
+
+static int strcmp_suffix(const char *str, const char *suffix)
+{
+       unsigned int len, suffix_len;
+
+       len = strlen(str);
+       suffix_len = strlen(suffix);
+       if (len <= suffix_len)
+               return -1;
+       return strcmp(str + len - suffix_len, suffix);
+}
+
+/**
+ * parse_suffix_prop_cells - Suffix property parsing function for suppliers
+ *
+ * @np:                Pointer to device tree node containing a list
+ * @prop_name: Name of property to be parsed. Expected to hold phandle values
+ * @index:     For properties holding a list of phandles, this is the index
+ *             into the list.
+ * @suffix:    Property suffix that is known to contain list of phandle(s) to
+ *             supplier(s)
+ * @cells_name:        property name that specifies phandles' arguments count
+ *
+ * This is a helper function to parse properties that have a known fixed suffix
+ * and are a list of phandles and phandle arguments.
+ *
+ * Returns:
+ * - phandle node pointer with refcount incremented. Caller must of_node_put()
+ *   on it when done.
+ * - NULL if no phandle found at index
+ */
+static struct device_node *parse_suffix_prop_cells(struct device_node *np,
+                                           const char *prop_name, int index,
+                                           const char *suffix,
+                                           const char *cells_name)
+{
+       struct of_phandle_args sup_args;
+
+       if (strcmp_suffix(prop_name, suffix))
+               return NULL;
+
+       if (of_parse_phandle_with_args(np, prop_name, cells_name, index,
+                                      &sup_args))
+               return NULL;
+
+       return sup_args.np;
+}
+
+#define DEFINE_SUFFIX_PROP(fname, suffix, cells)                            \
+static struct device_node *parse_##fname(struct device_node *np,            \
+                                       const char *prop_name, int index)    \
+{                                                                           \
+       return parse_suffix_prop_cells(np, prop_name, index, suffix, cells); \
+}
+
+/**
+ * struct supplier_bindings - Property parsing functions for suppliers
+ *
+ * @parse_prop: function name
+ *     parse_prop() finds the node corresponding to a supplier phandle
+ * @parse_prop.np: Pointer to device node holding supplier phandle property
+ * @parse_prop.prop_name: Name of property holding a phandle value
+ * @parse_prop.index: For properties holding a list of phandles, this is the
+ *                   index into the list
+ *
+ * Returns:
+ * parse_prop() return values are
+ * - phandle node pointer with refcount incremented. Caller must of_node_put()
+ *   on it when done.
+ * - NULL if no phandle found at index
+ */
+struct supplier_bindings {
+       struct device_node *(*parse_prop)(struct device_node *np,
+                                         const char *prop_name, int index);
+};
+
+DEFINE_SIMPLE_PROP(clocks, "clocks", "#clock-cells")
+DEFINE_SIMPLE_PROP(interconnects, "interconnects", "#interconnect-cells")
+DEFINE_SIMPLE_PROP(iommus, "iommus", "#iommu-cells")
+DEFINE_SIMPLE_PROP(mboxes, "mboxes", "#mbox-cells")
+DEFINE_SIMPLE_PROP(io_channels, "io-channel", "#io-channel-cells")
+DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
+
+static const struct supplier_bindings of_supplier_bindings[] = {
+       { .parse_prop = parse_clocks, },
+       { .parse_prop = parse_interconnects, },
+       { .parse_prop = parse_iommus, },
+       { .parse_prop = parse_mboxes, },
+       { .parse_prop = parse_io_channels, },
+       { .parse_prop = parse_regulators, },
+       {}
+};
+
+/**
+ * of_link_property - Create device links to suppliers listed in a property
+ * @dev: Consumer device
+ * @con_np: The consumer device tree node which contains the property
+ * @prop_name: Name of property to be parsed
+ *
+ * This function checks if the property @prop_name that is present in the
+ * @con_np device tree node is one of the known common device tree bindings
+ * that list phandles to suppliers. If @prop_name isn't one, this function
+ * doesn't do anything.
+ *
+ * If @prop_name is one, this function attempts to create device links from the
+ * consumer device @dev to all the devices of the suppliers listed in
+ * @prop_name.
+ *
+ * Any failed attempt to create a device link will NOT result in an immediate
+ * return.  of_link_property() must create links to all the available supplier
+ * devices even when attempts to create a link to one or more suppliers fail.
+ */
+static int of_link_property(struct device *dev, struct device_node *con_np,
+                            const char *prop_name)
+{
+       struct device_node *phandle;
+       const struct supplier_bindings *s = of_supplier_bindings;
+       unsigned int i = 0;
+       bool matched = false;
+       int ret = 0;
+       u32 dl_flags;
+
+       if (dev->of_node == con_np)
+               dl_flags = DL_FLAG_AUTOPROBE_CONSUMER;
+       else
+               dl_flags = DL_FLAG_SYNC_STATE_ONLY;
+
+       /* Do not stop at first failed link, link all available suppliers. */
+       while (!matched && s->parse_prop) {
+               while ((phandle = s->parse_prop(con_np, prop_name, i))) {
+                       matched = true;
+                       i++;
+                       if (of_link_to_phandle(dev, phandle, dl_flags)
+                                                               == -EAGAIN)
+                               ret = -EAGAIN;
+                       of_node_put(phandle);
+               }
+               s++;
+       }
+       return ret;
+}
+
+static int of_link_to_suppliers(struct device *dev,
+                                 struct device_node *con_np)
+{
+       struct device_node *child;
+       struct property *p;
+       int ret = 0;
+
+       for_each_property_of_node(con_np, p)
+               if (of_link_property(dev, con_np, p->name))
+                       ret = -ENODEV;
+
+       for_each_child_of_node(con_np, child)
+               if (of_link_to_suppliers(dev, child) && !ret)
+                       ret = -EAGAIN;
+
+       return ret;
+}
+
+static bool of_devlink;
+core_param(of_devlink, of_devlink, bool, 0);
+
+static int of_fwnode_add_links(const struct fwnode_handle *fwnode,
+                              struct device *dev)
+{
+       if (!of_devlink)
+               return 0;
+
+       if (unlikely(!is_of_node(fwnode)))
+               return 0;
+
+       return of_link_to_suppliers(dev, to_of_node(fwnode));
+}
+
 const struct fwnode_operations of_fwnode_ops = {
        .get = of_fwnode_get,
        .put = of_fwnode_put,
@@ -1001,5 +1298,6 @@ const struct fwnode_operations of_fwnode_ops = {
        .graph_get_remote_endpoint = of_fwnode_graph_get_remote_endpoint,
        .graph_get_port_parent = of_fwnode_graph_get_port_parent,
        .graph_parse_endpoint = of_fwnode_graph_parse_endpoint,
+       .add_links = of_fwnode_add_links,
 };
 EXPORT_SYMBOL_GPL(of_fwnode_ops);
index 22e5d4e13714e8635a54b74ab6c5f02f2c05bb2a..58bf9d496ba596dd59056a4ab4cb04863d75ac82 100644 (file)
@@ -54,6 +54,7 @@
 
 #ifdef CONFIG_SUPERH
 #include <asm/sh_bios.h>
+#include <asm/platform_early.h>
 #endif
 
 #include "serial_mctrl_gpio.h"
@@ -3090,6 +3091,7 @@ static struct console serial_console = {
        .data           = &sci_uart_driver,
 };
 
+#ifdef CONFIG_SUPERH
 static struct console early_serial_console = {
        .name           = "early_ttySC",
        .write          = serial_console_write,
@@ -3118,6 +3120,7 @@ static int sci_probe_earlyprintk(struct platform_device *pdev)
        register_console(&early_serial_console);
        return 0;
 }
+#endif
 
 #define SCI_CONSOLE    (&serial_console)
 
@@ -3318,8 +3321,10 @@ static int sci_probe(struct platform_device *dev)
         * the special early probe. We don't have sufficient device state
         * to make it beyond this yet.
         */
-       if (is_early_platform_device(dev))
+#ifdef CONFIG_SUPERH
+       if (is_sh_early_platform_device(dev))
                return sci_probe_earlyprintk(dev);
+#endif
 
        if (dev->dev.of_node) {
                p = sci_parse_dt(dev, &dev_id);
@@ -3414,8 +3419,8 @@ static void __exit sci_exit(void)
                uart_unregister_driver(&sci_uart_driver);
 }
 
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-early_platform_init_buffer("earlyprintk", &sci_driver,
+#if defined(CONFIG_SUPERH) && defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+sh_early_platform_init_buffer("earlyprintk", &sci_driver,
                           early_serial_buf, ARRAY_SIZE(early_serial_buf));
 #endif
 #ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
index 87846aad594b70ec06d6437b9c9bd3e56b6b43fd..dede25247b81f72a2f8aeca2f1c42e8f67683459 100644 (file)
@@ -420,20 +420,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
  * This function creates a file in debugfs with the given name that
  * contains the value of the variable @value.  If the @mode variable is so
  * set, it can be read from, and written to.
- *
- * This function will return a pointer to a dentry if it succeeds.  This
- * pointer must be passed to the debugfs_remove() function when the file is
- * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, %ERR_PTR(-ERROR) will be
- * returned.
- *
- * If debugfs is not enabled in the kernel, the value %ERR_PTR(-ENODEV) will
- * be returned.
  */
-struct dentry *debugfs_create_u8(const char *name, umode_t mode,
-                                struct dentry *parent, u8 *value)
+void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
+                      u8 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
                                   &fops_u8_ro, &fops_u8_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u8);
@@ -465,20 +456,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
  * This function creates a file in debugfs with the given name that
  * contains the value of the variable @value.  If the @mode variable is so
  * set, it can be read from, and written to.
- *
- * This function will return a pointer to a dentry if it succeeds.  This
- * pointer must be passed to the debugfs_remove() function when the file is
- * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, %ERR_PTR(-ERROR) will be
- * returned.
- *
- * If debugfs is not enabled in the kernel, the value %ERR_PTR(-ENODEV) will
- * be returned.
  */
-struct dentry *debugfs_create_u16(const char *name, umode_t mode,
-                                 struct dentry *parent, u16 *value)
+void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
+                       u16 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
                                   &fops_u16_ro, &fops_u16_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u16);
@@ -556,20 +538,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
  * This function creates a file in debugfs with the given name that
  * contains the value of the variable @value.  If the @mode variable is so
  * set, it can be read from, and written to.
- *
- * This function will return a pointer to a dentry if it succeeds.  This
- * pointer must be passed to the debugfs_remove() function when the file is
- * to be removed (no automatic cleanup happens if your module is unloaded,
- * you are responsible here.)  If an error occurs, %ERR_PTR(-ERROR) will be
- * returned.
- *
- * If debugfs is not enabled in the kernel, the value %ERR_PTR(-ENODEV) will
- * be returned.
  */
-struct dentry *debugfs_create_u64(const char *name, umode_t mode,
-                                struct dentry *parent, u64 *value)
+void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
+                       u64 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
                                   &fops_u64_ro, &fops_u64_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u64);
@@ -660,10 +633,10 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
  * @value: a pointer to the variable that the file should read to and write
  *         from.
  */
-struct dentry *debugfs_create_x8(const char *name, umode_t mode,
-                                struct dentry *parent, u8 *value)
+void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
+                      u8 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
                                   &fops_x8_ro, &fops_x8_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x8);
@@ -678,10 +651,10 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8);
  * @value: a pointer to the variable that the file should read to and write
  *         from.
  */
-struct dentry *debugfs_create_x16(const char *name, umode_t mode,
-                                struct dentry *parent, u16 *value)
+void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
+                       u16 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
                                   &fops_x16_ro, &fops_x16_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x16);
@@ -696,10 +669,10 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16);
  * @value: a pointer to the variable that the file should read to and write
  *         from.
  */
-struct dentry *debugfs_create_x32(const char *name, umode_t mode,
-                                struct dentry *parent, u32 *value)
+void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
+                       u32 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
                                   &fops_x32_ro, &fops_x32_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x32);
@@ -714,10 +687,10 @@ EXPORT_SYMBOL_GPL(debugfs_create_x32);
  * @value: a pointer to the variable that the file should read to and write
  *         from.
  */
-struct dentry *debugfs_create_x64(const char *name, umode_t mode,
-                                struct dentry *parent, u64 *value)
+void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
+                       u64 *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
                                   &fops_x64_ro, &fops_x64_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x64);
@@ -748,12 +721,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_size_t_wo, NULL, debugfs_size_t_set, "%llu\n");
  * @value: a pointer to the variable that the file should read to and write
  *         from.
  */
-struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
-                                    struct dentry *parent, size_t *value)
+void debugfs_create_size_t(const char *name, umode_t mode,
+                          struct dentry *parent, size_t *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value,
-                                       &fops_size_t, &fops_size_t_ro,
-                                       &fops_size_t_wo);
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_size_t,
+                                  &fops_size_t_ro, &fops_size_t_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_size_t);
 
@@ -785,12 +757,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set,
  * @value: a pointer to the variable that the file should read to and write
  *         from.
  */
-struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
-                                struct dentry *parent, atomic_t *value)
+void debugfs_create_atomic_t(const char *name, umode_t mode,
+                            struct dentry *parent, atomic_t *value)
 {
-       return debugfs_create_mode_unsafe(name, mode, parent, value,
-                                       &fops_atomic_t, &fops_atomic_t_ro,
-                                       &fops_atomic_t_wo);
+       debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
+                                  &fops_atomic_t_ro, &fops_atomic_t_wo);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
 
index 58424eb3b3291ae3183506d5d951ab425dccb51c..0e8f2e0cb91f1ee14ed178a5959be09d1f7b5caa 100644 (file)
@@ -97,28 +97,28 @@ ssize_t debugfs_attr_write(struct file *file, const char __user *buf,
 struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
                 struct dentry *new_dir, const char *new_name);
 
-struct dentry *debugfs_create_u8(const char *name, umode_t mode,
-                                struct dentry *parent, u8 *value);
-struct dentry *debugfs_create_u16(const char *name, umode_t mode,
-                                 struct dentry *parent, u16 *value);
+void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
+                      u8 *value);
+void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
+                       u16 *value);
 struct dentry *debugfs_create_u32(const char *name, umode_t mode,
                                  struct dentry *parent, u32 *value);
-struct dentry *debugfs_create_u64(const char *name, umode_t mode,
-                                 struct dentry *parent, u64 *value);
+void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
+                       u64 *value);
 struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
                                    struct dentry *parent, unsigned long *value);
-struct dentry *debugfs_create_x8(const char *name, umode_t mode,
-                                struct dentry *parent, u8 *value);
-struct dentry *debugfs_create_x16(const char *name, umode_t mode,
-                                 struct dentry *parent, u16 *value);
-struct dentry *debugfs_create_x32(const char *name, umode_t mode,
-                                 struct dentry *parent, u32 *value);
-struct dentry *debugfs_create_x64(const char *name, umode_t mode,
-                                 struct dentry *parent, u64 *value);
-struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
-                                    struct dentry *parent, size_t *value);
-struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
-                                    struct dentry *parent, atomic_t *value);
+void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
+                      u8 *value);
+void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
+                       u16 *value);
+void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
+                       u32 *value);
+void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
+                       u64 *value);
+void debugfs_create_size_t(const char *name, umode_t mode,
+                          struct dentry *parent, size_t *value);
+void debugfs_create_atomic_t(const char *name, umode_t mode,
+                            struct dentry *parent, atomic_t *value);
 struct dentry *debugfs_create_bool(const char *name, umode_t mode,
                                  struct dentry *parent, bool *value);
 
@@ -244,19 +244,11 @@ static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentr
        return ERR_PTR(-ENODEV);
 }
 
-static inline struct dentry *debugfs_create_u8(const char *name, umode_t mode,
-                                              struct dentry *parent,
-                                              u8 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_u8(const char *name, umode_t mode,
+                                    struct dentry *parent, u8 *value) { }
 
-static inline struct dentry *debugfs_create_u16(const char *name, umode_t mode,
-                                               struct dentry *parent,
-                                               u16 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_u16(const char *name, umode_t mode,
+                                     struct dentry *parent, u16 *value) { }
 
 static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode,
                                                struct dentry *parent,
@@ -265,12 +257,8 @@ static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode,
        return ERR_PTR(-ENODEV);
 }
 
-static inline struct dentry *debugfs_create_u64(const char *name, umode_t mode,
-                                               struct dentry *parent,
-                                               u64 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_u64(const char *name, umode_t mode,
+                                     struct dentry *parent, u64 *value) { }
 
 static inline struct dentry *debugfs_create_ulong(const char *name,
                                                umode_t mode,
@@ -280,46 +268,26 @@ static inline struct dentry *debugfs_create_ulong(const char *name,
        return ERR_PTR(-ENODEV);
 }
 
-static inline struct dentry *debugfs_create_x8(const char *name, umode_t mode,
-                                              struct dentry *parent,
-                                              u8 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x8(const char *name, umode_t mode,
+                                    struct dentry *parent, u8 *value) { }
 
-static inline struct dentry *debugfs_create_x16(const char *name, umode_t mode,
-                                               struct dentry *parent,
-                                               u16 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x16(const char *name, umode_t mode,
+                                     struct dentry *parent, u16 *value) { }
 
-static inline struct dentry *debugfs_create_x32(const char *name, umode_t mode,
-                                               struct dentry *parent,
-                                               u32 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x32(const char *name, umode_t mode,
+                                     struct dentry *parent, u32 *value) { }
 
-static inline struct dentry *debugfs_create_x64(const char *name, umode_t mode,
-                                               struct dentry *parent,
-                                               u64 *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_x64(const char *name, umode_t mode,
+                                     struct dentry *parent, u64 *value) { }
 
-static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mode,
-                                    struct dentry *parent,
-                                    size_t *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_size_t(const char *name, umode_t mode,
+                                        struct dentry *parent, size_t *value)
+{ }
 
-static inline struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
-                                    struct dentry *parent, atomic_t *value)
-{
-       return ERR_PTR(-ENODEV);
-}
+static inline void debugfs_create_atomic_t(const char *name, umode_t mode,
+                                          struct dentry *parent,
+                                          atomic_t *value)
+{ }
 
 static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode,
                                                 struct dentry *parent,
@@ -383,4 +351,25 @@ static inline ssize_t debugfs_write_file_bool(struct file *file,
 
 #endif
 
+/**
+ * debugfs_create_xul - create a debugfs file that is used to read and write an
+ * unsigned long value, formatted in hexadecimal
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this parameter is %NULL, then the
+ *          file will be created in the root of the debugfs filesystem.
+ * @value: a pointer to the variable that the file should read to and write
+ *         from.
+ */
+static inline void debugfs_create_xul(const char *name, umode_t mode,
+                                     struct dentry *parent,
+                                     unsigned long *value)
+{
+       if (sizeof(*value) == sizeof(u32))
+               debugfs_create_x32(name, mode, parent, (u32 *)value);
+       else
+               debugfs_create_x64(name, mode, parent, (u64 *)value);
+}
+
 #endif
index 297239a08bb77c7474c21695a8ef406cd582e78a..f05c5b92e61f535abcfd1d11fd6e8165a8ae840f 100644 (file)
@@ -80,6 +80,13 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
  *             that generate uevents to add the environment variables.
  * @probe:     Called when a new device or driver add to this bus, and callback
  *             the specific driver's probe to initial the matched device.
+ * @sync_state:        Called to sync device state to software state after all the
+ *             state tracking consumers linked to this device (present at
+ *             the time of late_initcall) have successfully bound to a
+ *             driver. If the device has no consumers, this function will
+ *             be called at late_initcall_sync level. If the device has
+ *             consumers that are never bound to a driver, this function
+ *             will never get called until they do.
  * @remove:    Called when a device removed from this bus.
  * @shutdown:  Called at shut-down time to quiesce the device.
  *
@@ -123,6 +130,7 @@ struct bus_type {
        int (*match)(struct device *dev, struct device_driver *drv);
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
        int (*probe)(struct device *dev);
+       void (*sync_state)(struct device *dev);
        int (*remove)(struct device *dev);
        void (*shutdown)(struct device *dev);
 
@@ -340,6 +348,13 @@ enum probe_type {
  * @probe:     Called to query the existence of a specific device,
  *             whether this driver can work with it, and bind the driver
  *             to a specific device.
+ * @sync_state:        Called to sync device state to software state after all the
+ *             state tracking consumers linked to this device (present at
+ *             the time of late_initcall) have successfully bound to a
+ *             driver. If the device has no consumers, this function will
+ *             be called at late_initcall_sync level. If the device has
+ *             consumers that are never bound to a driver, this function
+ *             will never get called until they do.
  * @remove:    Called when the device is removed from the system to
  *             unbind a device from this driver.
  * @shutdown:  Called at shut-down time to quiesce the device.
@@ -379,6 +394,7 @@ struct device_driver {
        const struct acpi_device_id     *acpi_match_table;
 
        int (*probe) (struct device *dev);
+       void (*sync_state)(struct device *dev);
        int (*remove) (struct device *dev);
        void (*shutdown) (struct device *dev);
        int (*suspend) (struct device *dev, pm_message_t state);
@@ -946,6 +962,8 @@ extern void devm_free_pages(struct device *dev, unsigned long addr);
 
 void __iomem *devm_ioremap_resource(struct device *dev,
                                    const struct resource *res);
+void __iomem *devm_ioremap_resource_wc(struct device *dev,
+                                      const struct resource *res);
 
 void __iomem *devm_of_iomap(struct device *dev,
                            struct device_node *node, int index,
@@ -1080,6 +1098,7 @@ enum device_link_state {
  * AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
  * AUTOPROBE_CONSUMER: Probe consumer driver automatically after supplier binds.
  * MANAGED: The core tracks presence of supplier/consumer drivers (internal).
+ * SYNC_STATE_ONLY: Link only affects sync_state() behavior.
  */
 #define DL_FLAG_STATELESS              BIT(0)
 #define DL_FLAG_AUTOREMOVE_CONSUMER    BIT(1)
@@ -1088,6 +1107,7 @@ enum device_link_state {
 #define DL_FLAG_AUTOREMOVE_SUPPLIER    BIT(4)
 #define DL_FLAG_AUTOPROBE_CONSUMER     BIT(5)
 #define DL_FLAG_MANAGED                        BIT(6)
+#define DL_FLAG_SYNC_STATE_ONLY                BIT(7)
 
 /**
  * struct device_link - Device link representation.
@@ -1135,11 +1155,18 @@ enum dl_dev_state {
  * struct dev_links_info - Device data related to device links.
  * @suppliers: List of links to supplier devices.
  * @consumers: List of links to consumer devices.
+ * @needs_suppliers: Hook to global list of devices waiting for suppliers.
+ * @defer_sync: Hook to global list of devices that have deferred sync_state.
+ * @need_for_probe: If needs_suppliers is on a list, this indicates if the
+ *                 suppliers are needed for probe or not.
  * @status: Driver status information.
  */
 struct dev_links_info {
        struct list_head suppliers;
        struct list_head consumers;
+       struct list_head needs_suppliers;
+       struct list_head defer_sync;
+       bool need_for_probe;
        enum dl_dev_state status;
 };
 
@@ -1215,6 +1242,9 @@ struct dev_links_info {
  * @offline:   Set after successful invocation of bus type's .offline().
  * @of_node_reused: Set if the device-tree node is shared with an ancestor
  *              device.
+ * @state_synced: The hardware state of this device has been synced to match
+ *               the software state of this device by calling the driver/bus
+ *               sync_state() callback.
  * @dma_coherent: this particular device is dma coherent, even if the
  *             architecture supports non-coherent devices.
  *
@@ -1311,6 +1341,7 @@ struct device {
        bool                    offline_disabled:1;
        bool                    offline:1;
        bool                    of_node_reused:1;
+       bool                    state_synced:1;
 #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \
     defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \
     defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
@@ -1653,6 +1684,8 @@ struct device_link *device_link_add(struct device *consumer,
                                    struct device *supplier, u32 flags);
 void device_link_del(struct device_link *link);
 void device_link_remove(void *consumer, struct device *supplier);
+void device_links_supplier_sync_state_pause(void);
+void device_links_supplier_sync_state_resume(void);
 
 #ifndef dev_fmt
 #define dev_fmt(fmt) fmt
index ababd6bc82f33cc75e5733c92ca6005f30a9bc16..766ff9bb58760bd5ce6342567d38435710b0cbed 100644 (file)
@@ -17,6 +17,7 @@ struct device;
 struct fwnode_handle {
        struct fwnode_handle *secondary;
        const struct fwnode_operations *ops;
+       struct device *dev;
 };
 
 /**
@@ -65,6 +66,43 @@ struct fwnode_reference_args {
  *                            endpoint node.
  * @graph_get_port_parent: Return the parent node of a port node.
  * @graph_parse_endpoint: Parse endpoint for port and endpoint id.
+ * @add_links: Called after the device corresponding to the fwnode is added
+ *             using device_add(). The function is expected to create device
+ *             links to all the suppliers of the device that are available at
+ *             the time this function is called.  The function must NOT stop
+ *             at the first failed device link if other unlinked supplier
+ *             devices are present in the system.  This is necessary for the
+ *             driver/bus sync_state() callbacks to work correctly.
+ *
+ *             For example, say Device-C depends on suppliers Device-S1 and
+ *             Device-S2 and the dependency is listed in that order in the
+ *             firmware.  Say, S1 gets populated from the firmware after
+ *             late_initcall_sync().  Say S2 is populated and probed way
+ *             before that in device_initcall(). When C is populated, if this
+ *             add_links() function doesn't continue past a "failed linking to
+ *             S1" and continue linking C to S2, then S2 will get a
+ *             sync_state() callback before C is probed. This is because from
+ *             the perspective of S2, C was never a consumer when its
+ *             sync_state() evaluation is done. To avoid this, the add_links()
+ *             function has to go through all available suppliers of the
+ *             device (that corresponds to this fwnode) and link to them
+ *             before returning.
+ *
+ *             If some suppliers are not yet available (indicated by an error
+ *             return value), this function will be called again when other
+ *             devices are added to allow creating device links to any newly
+ *             available suppliers.
+ *
+ *             Return 0 if device links have been successfully created to all
+ *             the suppliers this device needs to create device links to or if
+ *             the supplier information is not known.
+ *
+ *             Return -ENODEV if and only if the suppliers needed for probing
+ *             the device are not yet available to create device links to.
+ *
+ *             Return -EAGAIN if there are suppliers that need to be linked to
+ *             that are not yet available but none of those suppliers are
+ *             necessary for probing this device.
  */
 struct fwnode_operations {
        struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
@@ -102,6 +140,8 @@ struct fwnode_operations {
        (*graph_get_port_parent)(struct fwnode_handle *fwnode);
        int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode,
                                    struct fwnode_endpoint *endpoint);
+       int (*add_links)(const struct fwnode_handle *fwnode,
+                        struct device *dev);
 };
 
 #define fwnode_has_op(fwnode, op)                              \
@@ -123,5 +163,6 @@ struct fwnode_operations {
                if (fwnode_has_op(fwnode, op))                          \
                        (fwnode)->ops->op(fwnode, ## __VA_ARGS__);      \
        } while (false)
+#define get_dev_from_fwnode(fwnode)    get_device((fwnode)->dev)
 
 #endif
index f2688404d1cd73d3423d3443304a975306f4e0a1..276a03c246919ee57be5495808a4043c7abdcaac 100644 (file)
@@ -57,6 +57,12 @@ platform_find_device_by_driver(struct device *start,
 extern void __iomem *
 devm_platform_ioremap_resource(struct platform_device *pdev,
                               unsigned int index);
+extern void __iomem *
+devm_platform_ioremap_resource_wc(struct platform_device *pdev,
+                                 unsigned int index);
+extern void __iomem *
+devm_platform_ioremap_resource_byname(struct platform_device *pdev,
+                                     const char *name);
 extern int platform_get_irq(struct platform_device *, unsigned int);
 extern int platform_get_irq_optional(struct platform_device *, unsigned int);
 extern int platform_irq_count(struct platform_device *);
@@ -294,58 +300,6 @@ void platform_unregister_drivers(struct platform_driver * const *drivers,
 #define platform_register_drivers(drivers, count) \
        __platform_register_drivers(drivers, count, THIS_MODULE)
 
-/* early platform driver interface */
-struct early_platform_driver {
-       const char *class_str;
-       struct platform_driver *pdrv;
-       struct list_head list;
-       int requested_id;
-       char *buffer;
-       int bufsize;
-};
-
-#define EARLY_PLATFORM_ID_UNSET -2
-#define EARLY_PLATFORM_ID_ERROR -3
-
-extern int early_platform_driver_register(struct early_platform_driver *epdrv,
-                                         char *buf);
-extern void early_platform_add_devices(struct platform_device **devs, int num);
-
-static inline int is_early_platform_device(struct platform_device *pdev)
-{
-       return !pdev->dev.driver;
-}
-
-extern void early_platform_driver_register_all(char *class_str);
-extern int early_platform_driver_probe(char *class_str,
-                                      int nr_probe, int user_only);
-extern void early_platform_cleanup(void);
-
-#define early_platform_init(class_string, platdrv)             \
-       early_platform_init_buffer(class_string, platdrv, NULL, 0)
-
-#ifndef MODULE
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static __initdata struct early_platform_driver early_driver = {                \
-       .class_str = class_string,                                      \
-       .buffer = buf,                                                  \
-       .bufsize = bufsiz,                                              \
-       .pdrv = platdrv,                                                \
-       .requested_id = EARLY_PLATFORM_ID_UNSET,                        \
-};                                                                     \
-static int __init early_platform_driver_setup_func(char *buffer)       \
-{                                                                      \
-       return early_platform_driver_register(&early_driver, buffer);   \
-}                                                                      \
-early_param(class_string, early_platform_driver_setup_func)
-#else /* MODULE */
-#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \
-static inline char *early_platform_driver_setup_func(void)             \
-{                                                                      \
-       return bufsiz ? buf : NULL;                                     \
-}
-#endif /* MODULE */
-
 #ifdef CONFIG_SUSPEND
 extern int platform_pm_suspend(struct device *dev);
 extern int platform_pm_resume(struct device *dev);
@@ -380,4 +334,16 @@ extern int platform_dma_configure(struct device *dev);
 #define USE_PLATFORM_PM_SLEEP_OPS
 #endif
 
+#ifndef CONFIG_SUPERH
+/*
+ * REVISIT: This stub is needed for all non-SuperH users of early platform
+ * drivers. It should go away once we introduce the new platform_device-based
+ * early driver framework.
+ */
+static inline int is_sh_early_platform_device(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif /* CONFIG_SUPERH */
+
 #endif /* _PLATFORM_DEVICE_H_ */
index 48ceea867dd65274cb0d17eb4a536439ac4d40d2..d9b3cf0f410c8cfb509a4c1a4d6c83fde6fe33c6 100644 (file)
@@ -15,6 +15,7 @@ struct soc_device_attribute {
        const char *serial_number;
        const char *soc_id;
        const void *data;
+       const struct attribute_group *custom_attr_group;
 };
 
 /**
index 4ebfe0ac6c5b942e6078945b3a2fc9446db846bc..799cf823d493a3b358089bcaafb60f725f468be3 100644 (file)
@@ -33,6 +33,9 @@ struct gpiochip_info {
 #define GPIOLINE_FLAG_ACTIVE_LOW       (1UL << 2)
 #define GPIOLINE_FLAG_OPEN_DRAIN       (1UL << 3)
 #define GPIOLINE_FLAG_OPEN_SOURCE      (1UL << 4)
+#define GPIOLINE_FLAG_BIAS_PULL_UP     (1UL << 5)
+#define GPIOLINE_FLAG_BIAS_PULL_DOWN   (1UL << 6)
+#define GPIOLINE_FLAG_BIAS_DISABLE     (1UL << 7)
 
 /**
  * struct gpioline_info - Information about a certain GPIO line
@@ -62,6 +65,9 @@ struct gpioline_info {
 #define GPIOHANDLE_REQUEST_ACTIVE_LOW  (1UL << 2)
 #define GPIOHANDLE_REQUEST_OPEN_DRAIN  (1UL << 3)
 #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4)
+#define GPIOHANDLE_REQUEST_BIAS_PULL_UP        (1UL << 5)
+#define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN      (1UL << 6)
+#define GPIOHANDLE_REQUEST_BIAS_DISABLE        (1UL << 7)
 
 /**
  * struct gpiohandle_request - Information about a GPIO handle request
@@ -94,6 +100,24 @@ struct gpiohandle_request {
        int fd;
 };
 
+/**
+ * struct gpiohandle_config - Configuration for a GPIO handle request
+ * @flags: updated flags for the requested GPIO lines, such as
+ * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed
+ * together
+ * @default_values: if the GPIOHANDLE_REQUEST_OUTPUT is set in flags,
+ * this specifies the default output value, should be 0 (low) or
+ * 1 (high), anything else than 0 or 1 will be interpreted as 1 (high)
+ * @padding: reserved for future use and should be zero filled
+ */
+struct gpiohandle_config {
+       __u32 flags;
+       __u8 default_values[GPIOHANDLES_MAX];
+       __u32 padding[4]; /* padding for future use */
+};
+
+#define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0a, struct gpiohandle_config)
+
 /**
  * struct gpiohandle_data - Information of values on a GPIO handle
  * @values: when getting the state of lines this contains the current
index 6a0e9bd6524aecc06e2e1f3f3da202ec95374202..97fb44e5b4d6dce8a4a2f9d484f1f6ed1d431ed4 100644 (file)
@@ -114,25 +114,9 @@ void devm_iounmap(struct device *dev, void __iomem *addr)
 }
 EXPORT_SYMBOL(devm_iounmap);
 
-/**
- * devm_ioremap_resource() - check, request region, and ioremap resource
- * @dev: generic device to handle the resource for
- * @res: resource to be handled
- *
- * Checks that a resource is a valid memory region, requests the memory
- * region and ioremaps it. All operations are managed and will be undone
- * on driver detach.
- *
- * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
- * on failure. Usage example:
- *
- *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- *     base = devm_ioremap_resource(&pdev->dev, res);
- *     if (IS_ERR(base))
- *             return PTR_ERR(base);
- */
-void __iomem *devm_ioremap_resource(struct device *dev,
-                                   const struct resource *res)
+static void __iomem *
+__devm_ioremap_resource(struct device *dev, const struct resource *res,
+                       enum devm_ioremap_type type)
 {
        resource_size_t size;
        void __iomem *dest_ptr;
@@ -151,7 +135,7 @@ void __iomem *devm_ioremap_resource(struct device *dev,
                return IOMEM_ERR_PTR(-EBUSY);
        }
 
-       dest_ptr = devm_ioremap(dev, res->start, size);
+       dest_ptr = __devm_ioremap(dev, res->start, size, type);
        if (!dest_ptr) {
                dev_err(dev, "ioremap failed for resource %pR\n", res);
                devm_release_mem_region(dev, res->start, size);
@@ -160,8 +144,46 @@ void __iomem *devm_ioremap_resource(struct device *dev,
 
        return dest_ptr;
 }
+
+/**
+ * devm_ioremap_resource() - check, request region, and ioremap resource
+ * @dev: generic device to handle the resource for
+ * @res: resource to be handled
+ *
+ * Checks that a resource is a valid memory region, requests the memory
+ * region and ioremaps it. All operations are managed and will be undone
+ * on driver detach.
+ *
+ * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
+ * on failure. Usage example:
+ *
+ *     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ *     base = devm_ioremap_resource(&pdev->dev, res);
+ *     if (IS_ERR(base))
+ *             return PTR_ERR(base);
+ */
+void __iomem *devm_ioremap_resource(struct device *dev,
+                                   const struct resource *res)
+{
+       return __devm_ioremap_resource(dev, res, DEVM_IOREMAP);
+}
 EXPORT_SYMBOL(devm_ioremap_resource);
 
+/**
+ * devm_ioremap_resource_wc() - write-combined variant of
+ *                             devm_ioremap_resource()
+ * @dev: generic device to handle the resource for
+ * @res: resource to be handled
+ *
+ * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code
+ * on failure. Usage example:
+ */
+void __iomem *devm_ioremap_resource_wc(struct device *dev,
+                                      const struct resource *res)
+{
+       return __devm_ioremap_resource(dev, res, DEVM_IOREMAP_WC);
+}
+
 /*
  * devm_of_iomap - Requests a resource and maps the memory mapped IO
  *                for a given device_node managed by a given device
index c8ad20c28c438dabfffafb97263568202924922e..ca34dcdac8c0bd4d63816ecbf84f233278e7611e 100644 (file)
@@ -928,12 +928,7 @@ STA_OPS(he_capa);
                sta->debugfs_dir, sta, &sta_ ##name## _ops);
 
 #define DEBUGFS_ADD_COUNTER(name, field)                               \
-       if (sizeof(sta->field) == sizeof(u32))                          \
-               debugfs_create_u32(#name, 0400, sta->debugfs_dir,       \
-                       (u32 *) &sta->field);                           \
-       else                                                            \
-               debugfs_create_u64(#name, 0400, sta->debugfs_dir,       \
-                       (u64 *) &sta->field);
+       debugfs_create_ulong(#name, 0400, sta->debugfs_dir, &sta->field);
 
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
@@ -978,14 +973,8 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
                                    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
                DEBUGFS_ADD(airtime);
 
-       if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
-               debugfs_create_x32("driver_buffered_tids", 0400,
-                                  sta->debugfs_dir,
-                                  (u32 *)&sta->driver_buffered_tids);
-       else
-               debugfs_create_x64("driver_buffered_tids", 0400,
-                                  sta->debugfs_dir,
-                                  (u64 *)&sta->driver_buffered_tids);
+       debugfs_create_xul("driver_buffered_tids", 0400, sta->debugfs_dir,
+                          &sta->driver_buffered_tids);
 
        drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs_dir);
 }