]> Pileus Git - ~andy/linux/commitdiff
Merge remote-tracking branch 'regmap/topic/drivers' into regmap-next
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 14 Mar 2012 13:13:25 +0000 (13:13 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 14 Mar 2012 13:13:25 +0000 (13:13 +0000)
Resolved simple add/add conflicts:
drivers/base/regmap/internal.h
drivers/base/regmap/regmap.c

drivers/base/regmap/internal.h
drivers/base/regmap/regcache-lzo.c
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-debugfs.c
drivers/base/regmap/regmap.c
include/linux/regmap.h
include/trace/events/regmap.h

index d141b80479b5257d9fff00b9be47e47029e0f163..abd76678ed7309036c3b1e6091422bfba2078659 100644 (file)
@@ -22,6 +22,7 @@ struct regcache_ops;
 struct regmap_format {
        size_t buf_size;
        size_t reg_bytes;
+       size_t pad_bytes;
        size_t val_bytes;
        void (*format_write)(struct regmap *map,
                             unsigned int reg, unsigned int val);
@@ -65,16 +66,16 @@ struct regmap {
        unsigned int num_reg_defaults_raw;
 
        /* if set, only the cache is modified not the HW */
-       unsigned int cache_only:1;
+       u32 cache_only;
        /* if set, only the HW is modified not the cache */
-       unsigned int cache_bypass:1;
+       u32 cache_bypass;
        /* if set, remember to free reg_defaults_raw */
-       unsigned int cache_free:1;
+       bool cache_free;
 
        struct reg_default *reg_defaults;
        const void *reg_defaults_raw;
        void *cache;
-       bool cache_dirty;
+       u32 cache_dirty;
 
        struct reg_default *patch;
        int patch_regs;
index b7d16143edeb19b27ffe227535afdc9a555890d5..3025cf920f255b86bae2970638e695e69ef16441 100644 (file)
@@ -343,6 +343,12 @@ static int regcache_lzo_sync(struct regmap *map)
                ret = regcache_read(map, i, &val);
                if (ret)
                        return ret;
+
+               /* Is this the hardware default?  If so skip. */
+               ret = regcache_lookup_reg(map, i);
+               if (ret > 0 && val == map->reg_defaults[ret].def)
+                       continue;
+
                map->cache_bypass = 1;
                ret = _regmap_write(map, i, val);
                map->cache_bypass = 0;
index 32620c4f16834112ab88c9f9741750aee94f26d6..861ad2c81dff580fbf309f2b6eece8f15e1d769b 100644 (file)
@@ -377,7 +377,7 @@ static int regcache_rbtree_sync(struct regmap *map)
 
                        /* Is this the hardware default?  If so skip. */
                        ret = regcache_lookup_reg(map, i);
-                       if (ret > 0 && val == map->reg_defaults[ret].def)
+                       if (ret >= 0 && val == map->reg_defaults[ret].def)
                                continue;
 
                        map->cache_bypass = 1;
index e9032c3290675a79571a521aebd06c8cc3500426..8db713ffef66eed4eb4739f90af93eed4b616d7d 100644 (file)
@@ -211,7 +211,6 @@ int regcache_read(struct regmap *map,
 
        return -EINVAL;
 }
-EXPORT_SYMBOL_GPL(regcache_read);
 
 /**
  * regcache_write: Set the value of a given register in the cache.
@@ -238,7 +237,6 @@ int regcache_write(struct regmap *map,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(regcache_write);
 
 /**
  * regcache_sync: Sync the register cache with the hardware.
@@ -329,6 +327,7 @@ void regcache_cache_only(struct regmap *map, bool enable)
        mutex_lock(&map->lock);
        WARN_ON(map->cache_bypass && enable);
        map->cache_only = enable;
+       trace_regmap_cache_only(map->dev, enable);
        mutex_unlock(&map->lock);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -366,6 +365,7 @@ void regcache_cache_bypass(struct regmap *map, bool enable)
        mutex_lock(&map->lock);
        WARN_ON(map->cache_only && enable);
        map->cache_bypass = enable;
+       trace_regmap_cache_bypass(map->dev, enable);
        mutex_unlock(&map->lock);
 }
 EXPORT_SYMBOL_GPL(regcache_cache_bypass);
@@ -388,10 +388,16 @@ bool regcache_set_val(void *base, unsigned int idx,
                cache[idx] = val;
                break;
        }
+       case 4: {
+               u32 *cache = base;
+               if (cache[idx] == val)
+                       return true;
+               cache[idx] = val;
+               break;
+       }
        default:
                BUG();
        }
-       /* unreachable */
        return false;
 }
 
@@ -410,6 +416,10 @@ unsigned int regcache_get_val(const void *base, unsigned int idx,
                const u16 *cache = base;
                return cache[idx];
        }
+       case 4: {
+               const u32 *cache = base;
+               return cache[idx];
+       }
        default:
                BUG();
        }
index 6f397476e27c010fd938dfd05b84eb68fcef7c77..372f81a21201acc2f7540cb727809d01fe5c48b9 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
@@ -33,6 +32,35 @@ static int regmap_open_file(struct inode *inode, struct file *file)
        return 0;
 }
 
+static ssize_t regmap_name_read_file(struct file *file,
+                                    char __user *user_buf, size_t count,
+                                    loff_t *ppos)
+{
+       struct regmap *map = file->private_data;
+       int ret;
+       char *buf;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
+       if (ret < 0) {
+               kfree(buf);
+               return ret;
+       }
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations regmap_name_fops = {
+       .open = regmap_open_file,
+       .read = regmap_name_read_file,
+       .llseek = default_llseek,
+};
+
 static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
                                    size_t count, loff_t *ppos)
 {
@@ -103,9 +131,51 @@ out:
        return ret;
 }
 
+#undef REGMAP_ALLOW_WRITE_DEBUGFS
+#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+/*
+ * This can be dangerous especially when we have clients such as
+ * PMICs, therefore don't provide any real compile time configuration option
+ * for this feature, people who want to use this will need to modify
+ * the source code directly.
+ */
+static ssize_t regmap_map_write_file(struct file *file,
+                                    const char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       char buf[32];
+       size_t buf_size;
+       char *start = buf;
+       unsigned long reg, value;
+       struct regmap *map = file->private_data;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       while (*start == ' ')
+               start++;
+       reg = simple_strtoul(start, &start, 16);
+       while (*start == ' ')
+               start++;
+       if (strict_strtoul(start, 16, &value))
+               return -EINVAL;
+
+       /* Userspace has been fiddling around behind the kernel's back */
+       add_taint(TAINT_USER);
+
+       regmap_write(map, reg, value);
+       return buf_size;
+}
+#else
+#define regmap_map_write_file NULL
+#endif
+
 static const struct file_operations regmap_map_fops = {
        .open = regmap_open_file,
        .read = regmap_map_read_file,
+       .write = regmap_map_write_file,
        .llseek = default_llseek,
 };
 
@@ -186,12 +256,24 @@ void regmap_debugfs_init(struct regmap *map)
                return;
        }
 
+       debugfs_create_file("name", 0400, map->debugfs,
+                           map, &regmap_name_fops);
+
        if (map->max_register) {
                debugfs_create_file("registers", 0400, map->debugfs,
                                    map, &regmap_map_fops);
                debugfs_create_file("access", 0400, map->debugfs,
                                    map, &regmap_access_fops);
        }
+
+       if (map->cache_type) {
+               debugfs_create_bool("cache_only", 0400, map->debugfs,
+                                   &map->cache_only);
+               debugfs_create_bool("cache_dirty", 0400, map->debugfs,
+                                   &map->cache_dirty);
+               debugfs_create_bool("cache_bypass", 0400, map->debugfs,
+                                   &map->cache_bypass);
+       }
 }
 
 void regmap_debugfs_exit(struct regmap *map)
index 1752f13ddebc391b27dee4b791b9676de69f515d..e3ee9cabccb46d9ff31d2954715308c08007aedd 100644 (file)
@@ -10,8 +10,9 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/device.h>
 #include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/mutex.h>
 #include <linux/err.h>
 
@@ -36,6 +37,9 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
        if (map->max_register && reg > map->max_register)
                return false;
 
+       if (map->format.format_write)
+               return false;
+
        if (map->readable_reg)
                return map->readable_reg(map->dev, reg);
 
@@ -44,7 +48,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
 
 bool regmap_volatile(struct regmap *map, unsigned int reg)
 {
-       if (map->max_register && reg > map->max_register)
+       if (!regmap_readable(map, reg))
                return false;
 
        if (map->volatile_reg)
@@ -55,7 +59,7 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
 
 bool regmap_precious(struct regmap *map, unsigned int reg)
 {
-       if (map->max_register && reg > map->max_register)
+       if (!regmap_readable(map, reg))
                return false;
 
        if (map->precious_reg)
@@ -76,6 +80,14 @@ static bool regmap_volatile_range(struct regmap *map, unsigned int reg,
        return true;
 }
 
+static void regmap_format_2_6_write(struct regmap *map,
+                                    unsigned int reg, unsigned int val)
+{
+       u8 *out = map->work_buf;
+
+       *out = (reg << 6) | val;
+}
+
 static void regmap_format_4_12_write(struct regmap *map,
                                     unsigned int reg, unsigned int val)
 {
@@ -114,6 +126,13 @@ static void regmap_format_16(void *buf, unsigned int val)
        b[0] = cpu_to_be16(val);
 }
 
+static void regmap_format_32(void *buf, unsigned int val)
+{
+       __be32 *b = buf;
+
+       b[0] = cpu_to_be32(val);
+}
+
 static unsigned int regmap_parse_8(void *buf)
 {
        u8 *b = buf;
@@ -130,6 +149,15 @@ static unsigned int regmap_parse_16(void *buf)
        return b[0];
 }
 
+static unsigned int regmap_parse_32(void *buf)
+{
+       __be32 *b = buf;
+
+       b[0] = be32_to_cpu(b[0]);
+
+       return b[0];
+}
+
 /**
  * regmap_init(): Initialise register map
  *
@@ -159,8 +187,10 @@ struct regmap *regmap_init(struct device *dev,
 
        mutex_init(&map->lock);
        map->format.buf_size = (config->reg_bits + config->val_bits) / 8;
-       map->format.reg_bytes = config->reg_bits / 8;
-       map->format.val_bytes = config->val_bits / 8;
+       map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8);
+       map->format.pad_bytes = config->pad_bits / 8;
+       map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8);
+       map->format.buf_size += map->format.pad_bytes;
        map->dev = dev;
        map->bus = bus;
        map->max_register = config->max_register;
@@ -178,6 +208,16 @@ struct regmap *regmap_init(struct device *dev,
        }
 
        switch (config->reg_bits) {
+       case 2:
+               switch (config->val_bits) {
+               case 6:
+                       map->format.format_write = regmap_format_2_6_write;
+                       break;
+               default:
+                       goto err_map;
+               }
+               break;
+
        case 4:
                switch (config->val_bits) {
                case 12:
@@ -216,6 +256,10 @@ struct regmap *regmap_init(struct device *dev,
                map->format.format_reg = regmap_format_16;
                break;
 
+       case 32:
+               map->format.format_reg = regmap_format_32;
+               break;
+
        default:
                goto err_map;
        }
@@ -229,13 +273,17 @@ struct regmap *regmap_init(struct device *dev,
                map->format.format_val = regmap_format_16;
                map->format.parse_val = regmap_parse_16;
                break;
+       case 32:
+               map->format.format_val = regmap_format_32;
+               map->format.parse_val = regmap_parse_32;
+               break;
        }
 
        if (!map->format.format_write &&
            !(map->format.format_reg && map->format.format_val))
                goto err_map;
 
-       map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
+       map->work_buf = kzalloc(map->format.buf_size, GFP_KERNEL);
        if (map->work_buf == NULL) {
                ret = -ENOMEM;
                goto err_map;
@@ -315,6 +363,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
        mutex_lock(&map->lock);
 
        regcache_exit(map);
+       regmap_debugfs_exit(map);
 
        map->max_register = config->max_register;
        map->writeable_reg = config->writeable_reg;
@@ -323,6 +372,8 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
        map->precious_reg = config->precious_reg;
        map->cache_type = config->cache_type;
 
+       regmap_debugfs_init(map);
+
        map->cache_bypass = false;
        map->cache_only = false;
 
@@ -371,23 +422,28 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
         * send the work_buf directly, otherwise try to do a gather
         * write.
         */
-       if (val == map->work_buf + map->format.reg_bytes)
+       if (val == (map->work_buf + map->format.pad_bytes +
+                   map->format.reg_bytes))
                ret = map->bus->write(map->dev, map->work_buf,
-                                     map->format.reg_bytes + val_len);
+                                     map->format.reg_bytes +
+                                     map->format.pad_bytes +
+                                     val_len);
        else if (map->bus->gather_write)
                ret = map->bus->gather_write(map->dev, map->work_buf,
-                                            map->format.reg_bytes,
+                                            map->format.reg_bytes +
+                                            map->format.pad_bytes,
                                             val, val_len);
 
        /* If that didn't work fall back on linearising by hand. */
        if (ret == -ENOTSUPP) {
-               len = map->format.reg_bytes + val_len;
-               buf = kmalloc(len, GFP_KERNEL);
+               len = map->format.reg_bytes + map->format.pad_bytes + val_len;
+               buf = kzalloc(len, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
 
                memcpy(buf, map->work_buf, map->format.reg_bytes);
-               memcpy(buf + map->format.reg_bytes, val, val_len);
+               memcpy(buf + map->format.reg_bytes + map->format.pad_bytes,
+                      val, val_len);
                ret = map->bus->write(map->dev, buf, len);
 
                kfree(buf);
@@ -429,10 +485,12 @@ int _regmap_write(struct regmap *map, unsigned int reg,
 
                return ret;
        } else {
-               map->format.format_val(map->work_buf + map->format.reg_bytes,
-                                      val);
+               map->format.format_val(map->work_buf + map->format.reg_bytes
+                                      + map->format.pad_bytes, val);
                return _regmap_raw_write(map, reg,
-                                        map->work_buf + map->format.reg_bytes,
+                                        map->work_buf +
+                                        map->format.reg_bytes +
+                                        map->format.pad_bytes,
                                         map->format.val_bytes);
        }
 }
@@ -515,7 +573,8 @@ static int _regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
        trace_regmap_hw_read_start(map->dev, reg,
                                   val_len / map->format.val_bytes);
 
-       ret = map->bus->read(map->dev, map->work_buf, map->format.reg_bytes,
+       ret = map->bus->read(map->dev, map->work_buf,
+                            map->format.reg_bytes + map->format.pad_bytes,
                             val, val_len);
 
        trace_regmap_hw_read_done(map->dev, reg,
@@ -588,16 +647,32 @@ EXPORT_SYMBOL_GPL(regmap_read);
 int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
                    size_t val_len)
 {
-       size_t val_count = val_len / map->format.val_bytes;
-       int ret;
-
-       WARN_ON(!regmap_volatile_range(map, reg, val_count) &&
-               map->cache_type != REGCACHE_NONE);
+       size_t val_bytes = map->format.val_bytes;
+       size_t val_count = val_len / val_bytes;
+       unsigned int v;
+       int ret, i;
 
        mutex_lock(&map->lock);
 
-       ret = _regmap_raw_read(map, reg, val, val_len);
+       if (regmap_volatile_range(map, reg, val_count) || map->cache_bypass ||
+           map->cache_type == REGCACHE_NONE) {
+               /* Physical block read if there's no cache involved */
+               ret = _regmap_raw_read(map, reg, val, val_len);
+
+       } else {
+               /* Otherwise go word by word for the cache; should be low
+                * cost as we expect to hit the cache.
+                */
+               for (i = 0; i < val_count; i++) {
+                       ret = _regmap_read(map, reg + i, &v);
+                       if (ret != 0)
+                               goto out;
+
+                       map->format.format_val(val + (i * val_bytes), v);
+               }
+       }
 
+ out:
        mutex_unlock(&map->lock);
 
        return ret;
index 4a957fdb46f13c06156f4ded821d03287c11ba98..56ca477d5098fdbcb2f0122063b86b9195d0761d 100644 (file)
@@ -19,6 +19,7 @@
 struct module;
 struct i2c_client;
 struct spi_device;
+struct regmap;
 
 /* An enum of all the supported cache types */
 enum regcache_type {
@@ -40,10 +41,13 @@ struct reg_default {
        unsigned int def;
 };
 
+#ifdef CONFIG_REGMAP
+
 /**
  * Configuration for the register map of a device.
  *
  * @reg_bits: Number of bits in a register address, mandatory.
+ * @pad_bits: Number of bits of padding between register and value.
  * @val_bits: Number of bits in a register value, mandatory.
  *
  * @writeable_reg: Optional callback returning true if the register
@@ -74,6 +78,7 @@ struct reg_default {
  */
 struct regmap_config {
        int reg_bits;
+       int pad_bits;
        int val_bits;
 
        bool (*writeable_reg)(struct device *dev, unsigned int reg);
@@ -208,4 +213,115 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *data);
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data);
 
+#else
+
+/*
+ * These stubs should only ever be called by generic code which has
+ * regmap based facilities, if they ever get called at runtime
+ * something is going wrong and something probably needs to select
+ * REGMAP.
+ */
+
+static inline int regmap_write(struct regmap *map, unsigned int reg,
+                              unsigned int val)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_raw_write(struct regmap *map, unsigned int reg,
+                                  const void *val, size_t val_len)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_bulk_write(struct regmap *map, unsigned int reg,
+                                   const void *val, size_t val_count)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_read(struct regmap *map, unsigned int reg,
+                             unsigned int *val)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_raw_read(struct regmap *map, unsigned int reg,
+                                 void *val, size_t val_len)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_bulk_read(struct regmap *map, unsigned int reg,
+                                  void *val, size_t val_count)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_update_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_check(struct regmap *map,
+                                          unsigned int reg,
+                                          unsigned int mask, unsigned int val,
+                                          bool *change)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regmap_get_val_bytes(struct regmap *map)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regcache_sync(struct regmap *map)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline int regcache_sync_region(struct regmap *map, unsigned int min,
+                                      unsigned int max)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+static inline void regcache_cache_only(struct regmap *map, bool enable)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+}
+
+static inline void regcache_cache_bypass(struct regmap *map, bool enable)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+}
+
+static inline void regcache_mark_dirty(struct regmap *map)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+}
+
+static inline int regmap_register_patch(struct regmap *map,
+                                       const struct reg_default *regs,
+                                       int num_regs)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
+#endif
+
 #endif
index 12fbf43524e90e77759e80751bfe5ab983b4ad2d..d69738280ffadffe91e0e58f5a829dab49931b82 100644 (file)
@@ -139,6 +139,42 @@ TRACE_EVENT(regcache_sync,
                  __get_str(type), __get_str(status))
 );
 
+DECLARE_EVENT_CLASS(regmap_bool,
+
+       TP_PROTO(struct device *dev, bool flag),
+
+       TP_ARGS(dev, flag),
+
+       TP_STRUCT__entry(
+               __string(       name,           dev_name(dev)   )
+               __field(        int,            flag            )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, dev_name(dev));
+               __entry->flag = flag;
+       ),
+
+       TP_printk("%s flag=%d", __get_str(name),
+                 (int)__entry->flag)
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_only,
+
+       TP_PROTO(struct device *dev, bool flag),
+
+       TP_ARGS(dev, flag)
+
+);
+
+DEFINE_EVENT(regmap_bool, regmap_cache_bypass,
+
+       TP_PROTO(struct device *dev, bool flag),
+
+       TP_ARGS(dev, flag)
+
+);
+
 #endif /* _TRACE_REGMAP_H */
 
 /* This part must be outside protection */