summaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r--drivers/base/regmap/internal.h1
-rw-r--r--drivers/base/regmap/regmap-irq.c2
-rw-r--r--drivers/base/regmap/regmap.c64
3 files changed, 66 insertions, 1 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 2eb719704885..b986b8660b0c 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -45,6 +45,7 @@ struct regmap {
struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus;
void *bus_context;
+ const char *name;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index fc69d29d272a..0d233cc1c7fa 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -206,6 +206,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d)
return -ENOMEM;
+ *data = d;
+
d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->status_buf)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 357294905793..0bcda488f11c 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -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;
}
OpenPOWER on IntegriCloud