]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/base/regmap/regmap.c
Merge branches 'regmap-core', 'regmap-stride', 'regmap-mmio' and 'regmap-irq' into...
[karo-tx-linux.git] / drivers / base / regmap / regmap.c
index 357294905793c840aea6826262bbab4dda2d3660..0bcda488f11cd45e6252e113ffd025b058309e99 100644 (file)
@@ -199,6 +199,15 @@ static void regmap_unlock_spinlock(struct regmap *map)
        spin_unlock(&map->spinlock);
 }
 
+static void dev_get_regmap_release(struct device *dev, void *res)
+{
+       /*
+        * We don't actually have anything to do here; the goal here
+        * is not to manage the regmap but to provide a simple way to
+        * get the regmap back given a struct device.
+        */
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -216,7 +225,7 @@ struct regmap *regmap_init(struct device *dev,
                           void *bus_context,
                           const struct regmap_config *config)
 {
-       struct regmap *map;
+       struct regmap *map, **m;
        int ret = -EINVAL;
 
        if (!bus || !config)
@@ -257,6 +266,7 @@ struct regmap *regmap_init(struct device *dev,
        map->volatile_reg = config->volatile_reg;
        map->precious_reg = config->precious_reg;
        map->cache_type = config->cache_type;
+       map->name = config->name;
 
        if (config->read_flag_mask || config->write_flag_mask) {
                map->read_flag_mask = config->read_flag_mask;
@@ -360,8 +370,19 @@ struct regmap *regmap_init(struct device *dev,
        if (ret < 0)
                goto err_free_workbuf;
 
+       /* Add a devres resource for dev_get_regmap() */
+       m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
+       if (!m) {
+               ret = -ENOMEM;
+               goto err_cache;
+       }
+       *m = map;
+       devres_add(dev, m);
+
        return map;
 
+err_cache:
+       regcache_exit(map);
 err_free_workbuf:
        kfree(map->work_buf);
 err_map:
@@ -465,6 +486,44 @@ void regmap_exit(struct regmap *map)
 }
 EXPORT_SYMBOL_GPL(regmap_exit);
 
+static int dev_get_regmap_match(struct device *dev, void *res, void *data)
+{
+       struct regmap **r = res;
+       if (!r || !*r) {
+               WARN_ON(!r || !*r);
+               return 0;
+       }
+
+       /* If the user didn't specify a name match any */
+       if (data)
+               return (*r)->name == data;
+       else
+               return 1;
+}
+
+/**
+ * dev_get_regmap(): Obtain the regmap (if any) for a device
+ *
+ * @dev: Device to retrieve the map for
+ * @name: Optional name for the register map, usually NULL.
+ *
+ * Returns the regmap for the device if one is present, or NULL.  If
+ * name is specified then it must match the name specified when
+ * registering the device, if it is NULL then the first regmap found
+ * will be used.  Devices with multiple register maps are very rare,
+ * generic code should normally not need to specify a name.
+ */
+struct regmap *dev_get_regmap(struct device *dev, const char *name)
+{
+       struct regmap **r = devres_find(dev, dev_get_regmap_release,
+                                       dev_get_regmap_match, (void *)name);
+
+       if (!r)
+               return NULL;
+       return *r;
+}
+EXPORT_SYMBOL_GPL(dev_get_regmap);
+
 static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                             const void *val, size_t val_len)
 {
@@ -768,6 +827,9 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
                trace_regmap_reg_read(map->dev, reg, *val);
        }
 
+       if (ret == 0 && !map->cache_bypass)
+               regcache_write(map, reg, *val);
+
        return ret;
 }