summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--drivers/mfd/da9052-core.c8
-rw-r--r--include/linux/mfd/da9052/da9052.h1
-rw-r--r--include/linux/regmap.h8
6 files changed, 78 insertions, 6 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;
}
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
index 7ff313fe9fb1..7776aff46269 100644
--- a/drivers/mfd/da9052-core.c
+++ b/drivers/mfd/da9052-core.c
@@ -659,12 +659,11 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
da9052->irq_base, &da9052_regmap_irq_chip,
- NULL);
+ &da9052->irq_data);
if (ret < 0)
goto regmap_err;
- desc = irq_to_desc(da9052->chip_irq);
- da9052->irq_base = regmap_irq_chip_get_base(desc->action->dev_id);
+ da9052->irq_base = regmap_irq_chip_get_base(da9052->irq_data);
ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
ARRAY_SIZE(da9052_subdev_info), NULL, 0);
@@ -681,8 +680,7 @@ regmap_err:
void da9052_device_exit(struct da9052 *da9052)
{
- regmap_del_irq_chip(da9052->chip_irq,
- irq_get_irq_data(da9052->irq_base)->chip_data);
+ regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data);
mfd_remove_devices(da9052->dev);
}
diff --git a/include/linux/mfd/da9052/da9052.h b/include/linux/mfd/da9052/da9052.h
index 7ffbd6e9e7fc..8313cd9658e3 100644
--- a/include/linux/mfd/da9052/da9052.h
+++ b/include/linux/mfd/da9052/da9052.h
@@ -80,6 +80,7 @@ struct da9052 {
struct regmap *regmap;
int irq_base;
+ struct regmap_irq_chip_data *irq_data;
u8 chip_id;
int chip_irq;
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index ae797b142aa8..9dbc9a1bec43 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -170,6 +170,7 @@ struct regmap *devm_regmap_init_mmio(struct device *dev,
void regmap_exit(struct regmap *map);
int regmap_reinit_cache(struct regmap *map,
const struct regmap_config *config);
+struct regmap *dev_get_regmap(struct device *dev, const char *name);
int regmap_write(struct regmap *map, unsigned int reg, unsigned int val);
int regmap_raw_write(struct regmap *map, unsigned int reg,
const void *val, size_t val_len);
@@ -354,6 +355,13 @@ static inline int regmap_register_patch(struct regmap *map,
return -EINVAL;
}
+static inline struct regmap *dev_get_regmap(struct device *dev,
+ const char *name)
+{
+ WARN_ONCE(1, "regmap API is disabled");
+ return NULL;
+}
+
#endif
#endif