Merge remote-tracking branches 'regmap/topic/debugfs' and 'regmap/topic/force-update...
authorMark Brown <broonie@kernel.org>
Fri, 4 Sep 2015 16:22:09 +0000 (17:22 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 4 Sep 2015 16:22:09 +0000 (17:22 +0100)
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
drivers/regulator/core.c
fs/debugfs/file.c
include/linux/debugfs.h
include/linux/regmap.h

index 5799a0b..f42f2ba 100644 (file)
@@ -469,6 +469,87 @@ static const struct file_operations regmap_access_fops = {
        .llseek = default_llseek,
 };
 
+static ssize_t regmap_cache_only_write_file(struct file *file,
+                                           const char __user *user_buf,
+                                           size_t count, loff_t *ppos)
+{
+       struct regmap *map = container_of(file->private_data,
+                                         struct regmap, cache_only);
+       ssize_t result;
+       bool was_enabled, require_sync = false;
+       int err;
+
+       map->lock(map->lock_arg);
+
+       was_enabled = map->cache_only;
+
+       result = debugfs_write_file_bool(file, user_buf, count, ppos);
+       if (result < 0) {
+               map->unlock(map->lock_arg);
+               return result;
+       }
+
+       if (map->cache_only && !was_enabled) {
+               dev_warn(map->dev, "debugfs cache_only=Y forced\n");
+               add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+       } else if (!map->cache_only && was_enabled) {
+               dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n");
+               require_sync = true;
+       }
+
+       map->unlock(map->lock_arg);
+
+       if (require_sync) {
+               err = regcache_sync(map);
+               if (err)
+                       dev_err(map->dev, "Failed to sync cache %d\n", err);
+       }
+
+       return result;
+}
+
+static const struct file_operations regmap_cache_only_fops = {
+       .open = simple_open,
+       .read = debugfs_read_file_bool,
+       .write = regmap_cache_only_write_file,
+};
+
+static ssize_t regmap_cache_bypass_write_file(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       struct regmap *map = container_of(file->private_data,
+                                         struct regmap, cache_bypass);
+       ssize_t result;
+       bool was_enabled;
+
+       map->lock(map->lock_arg);
+
+       was_enabled = map->cache_bypass;
+
+       result = debugfs_write_file_bool(file, user_buf, count, ppos);
+       if (result < 0)
+               goto out;
+
+       if (map->cache_bypass && !was_enabled) {
+               dev_warn(map->dev, "debugfs cache_bypass=Y forced\n");
+               add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+       } else if (!map->cache_bypass && was_enabled) {
+               dev_warn(map->dev, "debugfs cache_bypass=N forced\n");
+       }
+
+out:
+       map->unlock(map->lock_arg);
+
+       return result;
+}
+
+static const struct file_operations regmap_cache_bypass_fops = {
+       .open = simple_open,
+       .read = debugfs_read_file_bool,
+       .write = regmap_cache_bypass_write_file,
+};
+
 void regmap_debugfs_init(struct regmap *map, const char *name)
 {
        struct rb_node *next;
@@ -518,10 +599,11 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
        if (map->max_register || regmap_readable(map, 0)) {
                umode_t registers_mode;
 
-               if (IS_ENABLED(REGMAP_ALLOW_WRITE_DEBUGFS))
-                       registers_mode = 0600;
-               else
-                       registers_mode = 0400;
+#if defined(REGMAP_ALLOW_WRITE_DEBUGFS)
+               registers_mode = 0600;
+#else
+               registers_mode = 0400;
+#endif
 
                debugfs_create_file("registers", registers_mode, map->debugfs,
                                    map, &regmap_map_fops);
@@ -530,12 +612,13 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
        }
 
        if (map->cache_type) {
-               debugfs_create_bool("cache_only", 0400, map->debugfs,
-                                   &map->cache_only);
+               debugfs_create_file("cache_only", 0600, map->debugfs,
+                                   &map->cache_only, &regmap_cache_only_fops);
                debugfs_create_bool("cache_dirty", 0400, map->debugfs,
                                    &map->cache_dirty);
-               debugfs_create_bool("cache_bypass", 0400, map->debugfs,
-                                   &map->cache_bypass);
+               debugfs_create_file("cache_bypass", 0600, map->debugfs,
+                                   &map->cache_bypass,
+                                   &regmap_cache_bypass_fops);
        }
 
        next = rb_first(&map->range_tree);
index 93d2e23..4dd571f 100644 (file)
@@ -34,7 +34,7 @@
 
 static int _regmap_update_bits(struct regmap *map, unsigned int reg,
                               unsigned int mask, unsigned int val,
-                              bool *change);
+                              bool *change, bool force_write);
 
 static int _regmap_bus_reg_read(void *context, unsigned int reg,
                                unsigned int *val);
@@ -1186,7 +1186,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
                ret = _regmap_update_bits(map, range->selector_reg,
                                          range->selector_mask,
                                          win_page << range->selector_shift,
-                                         &page_chg);
+                                         &page_chg, false);
 
                map->work_buf = orig_work_buf;
 
@@ -1657,6 +1657,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id,
 }
 EXPORT_SYMBOL_GPL(regmap_fields_write);
 
+int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
+                       unsigned int val)
+{
+       if (id >= field->id_size)
+               return -EINVAL;
+
+       return regmap_write_bits(field->regmap,
+                                 field->reg + (field->id_offset * id),
+                                 field->mask, val << field->shift);
+}
+EXPORT_SYMBOL_GPL(regmap_fields_force_write);
+
 /**
  * regmap_fields_update_bits():        Perform a read/modify/write cycle
  *                              on the register field
@@ -2466,7 +2478,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read);
 
 static int _regmap_update_bits(struct regmap *map, unsigned int reg,
                               unsigned int mask, unsigned int val,
-                              bool *change)
+                              bool *change, bool force_write)
 {
        int ret;
        unsigned int tmp, orig;
@@ -2478,7 +2490,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
        tmp = orig & ~mask;
        tmp |= val & mask;
 
-       if (tmp != orig) {
+       if (force_write || (tmp != orig)) {
                ret = _regmap_write(map, reg, tmp);
                if (change)
                        *change = true;
@@ -2506,13 +2518,36 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
        int ret;
 
        map->lock(map->lock_arg);
-       ret = _regmap_update_bits(map, reg, mask, val, NULL);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
        map->unlock(map->lock_arg);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits);
 
+/**
+ * regmap_write_bits: Perform a read/modify/write cycle on the register map
+ *
+ * @map: Register map to update
+ * @reg: Register to update
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * Returns zero for success, a negative number on error.
+ */
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+                     unsigned int mask, unsigned int val)
+{
+       int ret;
+
+       map->lock(map->lock_arg);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
+       map->unlock(map->lock_arg);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_write_bits);
+
 /**
  * regmap_update_bits_async: Perform a read/modify/write cycle on the register
  *                           map asynchronously
@@ -2537,7 +2572,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg,
 
        map->async = true;
 
-       ret = _regmap_update_bits(map, reg, mask, val, NULL);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
 
        map->async = false;
 
@@ -2566,7 +2601,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
        int ret;
 
        map->lock(map->lock_arg);
-       ret = _regmap_update_bits(map, reg, mask, val, change);
+       ret = _regmap_update_bits(map, reg, mask, val, change, false);
        map->unlock(map->lock_arg);
        return ret;
 }
@@ -2599,7 +2634,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 
        map->async = true;
 
-       ret = _regmap_update_bits(map, reg, mask, val, change);
+       ret = _regmap_update_bits(map, reg, mask, val, change, false);
 
        map->async = false;
 
index 78387a6..3c3137a 100644 (file)
@@ -1244,7 +1244,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev,
        regulator->debugfs = debugfs_create_dir(regulator->supply_name,
                                                rdev->debugfs);
        if (!regulator->debugfs) {
-               rdev_warn(rdev, "Failed to create debugfs directory\n");
+               rdev_dbg(rdev, "Failed to create debugfs directory\n");
        } else {
                debugfs_create_u32("uA_load", 0444, regulator->debugfs,
                                   &regulator->uA_load);
index 284f9aa..6c55ade 100644 (file)
@@ -435,8 +435,8 @@ struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
 }
 EXPORT_SYMBOL_GPL(debugfs_create_atomic_t);
 
-static ssize_t read_file_bool(struct file *file, char __user *user_buf,
-                             size_t count, loff_t *ppos)
+ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
 {
        char buf[3];
        u32 *val = file->private_data;
@@ -449,9 +449,10 @@ static ssize_t read_file_bool(struct file *file, char __user *user_buf,
        buf[2] = 0x00;
        return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
 }
+EXPORT_SYMBOL_GPL(debugfs_read_file_bool);
 
-static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
-                              size_t count, loff_t *ppos)
+ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
+                               size_t count, loff_t *ppos)
 {
        char buf[32];
        size_t buf_size;
@@ -468,10 +469,11 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
 
        return count;
 }
+EXPORT_SYMBOL_GPL(debugfs_write_file_bool);
 
 static const struct file_operations fops_bool = {
-       .read =         read_file_bool,
-       .write =        write_file_bool,
+       .read =         debugfs_read_file_bool,
+       .write =        debugfs_write_file_bool,
        .open =         simple_open,
        .llseek =       default_llseek,
 };
index 420311b..9beb636 100644 (file)
@@ -116,6 +116,12 @@ struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name,
 
 bool debugfs_initialized(void);
 
+ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos);
+
+ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
+                               size_t count, loff_t *ppos);
+
 #else
 
 #include <linux/err.h>
@@ -282,6 +288,20 @@ static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev,
        return ERR_PTR(-ENODEV);
 }
 
+static inline ssize_t debugfs_read_file_bool(struct file *file,
+                                            char __user *user_buf,
+                                            size_t count, loff_t *ppos)
+{
+       return -ENODEV;
+}
+
+static inline ssize_t debugfs_write_file_bool(struct file *file,
+                                             const char __user *user_buf,
+                                             size_t count, loff_t *ppos)
+{
+       return -ENODEV;
+}
+
 #endif
 
 #endif
index 6724d0e..e0fb86b 100644 (file)
@@ -431,6 +431,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                     size_t val_count);
 int regmap_update_bits(struct regmap *map, unsigned int reg,
                       unsigned int mask, unsigned int val);
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+                      unsigned int mask, unsigned int val);
 int regmap_update_bits_async(struct regmap *map, unsigned int reg,
                             unsigned int mask, unsigned int val);
 int regmap_update_bits_check(struct regmap *map, unsigned int reg,
@@ -512,6 +514,8 @@ int regmap_field_update_bits(struct regmap_field *field,
 
 int regmap_fields_write(struct regmap_field *field, unsigned int id,
                        unsigned int val);
+int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
+                       unsigned int val);
 int regmap_fields_read(struct regmap_field *field, unsigned int id,
                       unsigned int *val);
 int regmap_fields_update_bits(struct regmap_field *field,  unsigned int id,
@@ -654,6 +658,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
        return -EINVAL;
 }
 
+static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
+                                    unsigned int mask, unsigned int val)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
 static inline int regmap_update_bits_async(struct regmap *map,
                                           unsigned int reg,
                                           unsigned int mask, unsigned int val)