]> Pileus Git - ~andy/linux/blobdiff - drivers/base/regmap/regmap.c
Merge branches 'regmap-core', 'regmap-irq' and 'regmap-page' into regmap-next
[~andy/linux] / drivers / base / regmap / regmap.c
index d912eb2d19cec9687655759e98003b25865dff28..c241ae2f2f10b91e8998e5b657d5f739cc0c0b7b 100644 (file)
 
 #include "internal.h"
 
+/*
+ * Sometimes for failures during very early init the trace
+ * infrastructure isn't available early enough to be used.  For this
+ * sort of problem defining LOG_DEVICE will add printks for basic
+ * register I/O on a specific device.
+ */
+#undef LOG_DEVICE
+
 static int _regmap_update_bits(struct regmap *map, unsigned int reg,
                               unsigned int mask, unsigned int val,
                               bool *change);
@@ -124,13 +132,19 @@ static void regmap_format_8(void *buf, unsigned int val, unsigned int shift)
        b[0] = val << shift;
 }
 
-static void regmap_format_16(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_16_be(void *buf, unsigned int val, unsigned int shift)
 {
        __be16 *b = buf;
 
        b[0] = cpu_to_be16(val << shift);
 }
 
+static void regmap_format_16_native(void *buf, unsigned int val,
+                                   unsigned int shift)
+{
+       *(u16 *)buf = val << shift;
+}
+
 static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
 {
        u8 *b = buf;
@@ -142,13 +156,19 @@ static void regmap_format_24(void *buf, unsigned int val, unsigned int shift)
        b[2] = val;
 }
 
-static void regmap_format_32(void *buf, unsigned int val, unsigned int shift)
+static void regmap_format_32_be(void *buf, unsigned int val, unsigned int shift)
 {
        __be32 *b = buf;
 
        b[0] = cpu_to_be32(val << shift);
 }
 
+static void regmap_format_32_native(void *buf, unsigned int val,
+                                   unsigned int shift)
+{
+       *(u32 *)buf = val << shift;
+}
+
 static unsigned int regmap_parse_8(void *buf)
 {
        u8 *b = buf;
@@ -156,7 +176,7 @@ static unsigned int regmap_parse_8(void *buf)
        return b[0];
 }
 
-static unsigned int regmap_parse_16(void *buf)
+static unsigned int regmap_parse_16_be(void *buf)
 {
        __be16 *b = buf;
 
@@ -165,6 +185,11 @@ static unsigned int regmap_parse_16(void *buf)
        return b[0];
 }
 
+static unsigned int regmap_parse_16_native(void *buf)
+{
+       return *(u16 *)buf;
+}
+
 static unsigned int regmap_parse_24(void *buf)
 {
        u8 *b = buf;
@@ -175,7 +200,7 @@ static unsigned int regmap_parse_24(void *buf)
        return ret;
 }
 
-static unsigned int regmap_parse_32(void *buf)
+static unsigned int regmap_parse_32_be(void *buf)
 {
        __be32 *b = buf;
 
@@ -184,6 +209,11 @@ static unsigned int regmap_parse_32(void *buf)
        return b[0];
 }
 
+static unsigned int regmap_parse_32_native(void *buf)
+{
+       return *(u32 *)buf;
+}
+
 static void regmap_lock_mutex(struct regmap *map)
 {
        mutex_lock(&map->mutex);
@@ -293,6 +323,7 @@ struct regmap *regmap_init(struct device *dev,
 {
        struct regmap *map, **m;
        int ret = -EINVAL;
+       enum regmap_endian reg_endian, val_endian;
        int i, j;
 
        if (!bus || !config)
@@ -342,6 +373,18 @@ struct regmap *regmap_init(struct device *dev,
                map->read_flag_mask = bus->read_flag_mask;
        }
 
+       reg_endian = config->reg_format_endian;
+       if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+               reg_endian = bus->reg_format_endian_default;
+       if (reg_endian == REGMAP_ENDIAN_DEFAULT)
+               reg_endian = REGMAP_ENDIAN_BIG;
+
+       val_endian = config->val_format_endian;
+       if (val_endian == REGMAP_ENDIAN_DEFAULT)
+               val_endian = bus->val_format_endian_default;
+       if (val_endian == REGMAP_ENDIAN_DEFAULT)
+               val_endian = REGMAP_ENDIAN_BIG;
+
        switch (config->reg_bits + map->reg_shift) {
        case 2:
                switch (config->val_bits) {
@@ -388,11 +431,29 @@ struct regmap *regmap_init(struct device *dev,
                break;
 
        case 16:
-               map->format.format_reg = regmap_format_16;
+               switch (reg_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_reg = regmap_format_16_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_reg = regmap_format_16_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
 
        case 32:
-               map->format.format_reg = regmap_format_32;
+               switch (reg_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_reg = regmap_format_32_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_reg = regmap_format_32_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
 
        default:
@@ -405,21 +466,47 @@ struct regmap *regmap_init(struct device *dev,
                map->format.parse_val = regmap_parse_8;
                break;
        case 16:
-               map->format.format_val = regmap_format_16;
-               map->format.parse_val = regmap_parse_16;
+               switch (val_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_val = regmap_format_16_be;
+                       map->format.parse_val = regmap_parse_16_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_val = regmap_format_16_native;
+                       map->format.parse_val = regmap_parse_16_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
        case 24:
+               if (val_endian != REGMAP_ENDIAN_BIG)
+                       goto err_map;
                map->format.format_val = regmap_format_24;
                map->format.parse_val = regmap_parse_24;
                break;
        case 32:
-               map->format.format_val = regmap_format_32;
-               map->format.parse_val = regmap_parse_32;
+               switch (val_endian) {
+               case REGMAP_ENDIAN_BIG:
+                       map->format.format_val = regmap_format_32_be;
+                       map->format.parse_val = regmap_parse_32_be;
+                       break;
+               case REGMAP_ENDIAN_NATIVE:
+                       map->format.format_val = regmap_format_32_native;
+                       map->format.parse_val = regmap_parse_32_native;
+                       break;
+               default:
+                       goto err_map;
+               }
                break;
        }
 
-       if (map->format.format_write)
+       if (map->format.format_write) {
+               if ((reg_endian != REGMAP_ENDIAN_BIG) ||
+                   (val_endian != REGMAP_ENDIAN_BIG))
+                       goto err_map;
                map->use_single_rw = true;
+       }
 
        if (!map->format.format_write &&
            !(map->format.format_reg && map->format.format_val))
@@ -807,6 +894,11 @@ int _regmap_write(struct regmap *map, unsigned int reg,
                }
        }
 
+#ifdef LOG_DEVICE
+       if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
+               dev_info(map->dev, "%x <= %x\n", reg, val);
+#endif
+
        trace_regmap_reg_write(map->dev, reg, val);
 
        if (map->format.format_write) {
@@ -1018,6 +1110,12 @@ static int _regmap_read(struct regmap *map, unsigned int reg,
        ret = _regmap_raw_read(map, reg, map->work_buf, map->format.val_bytes);
        if (ret == 0) {
                *val = map->format.parse_val(map->work_buf);
+
+#ifdef LOG_DEVICE
+               if (strcmp(dev_name(map->dev), LOG_DEVICE) == 0)
+                       dev_info(map->dev, "%x => %x\n", reg, *val);
+#endif
+
                trace_regmap_reg_read(map->dev, reg, *val);
        }