Merge remote-tracking branches 'regmap/topic/bulk', 'regmap/topic/i2c', 'regmap/topic...
authorMark Brown <broonie@kernel.org>
Fri, 15 Jul 2016 12:44:47 +0000 (13:44 +0100)
committerMark Brown <broonie@kernel.org>
Fri, 15 Jul 2016 12:44:47 +0000 (13:44 +0100)
MAINTAINERS
drivers/base/regmap/regmap-i2c.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
include/linux/regmap.h

index 1209323..f98a0c6 100644 (file)
@@ -9600,6 +9600,7 @@ M:        Mark Brown <broonie@kernel.org>
 L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
 S:     Supported
+F:     Documentation/devicetree/bindings/regmap/
 F:     drivers/base/regmap/
 F:     include/linux/regmap.h
 
index 1a8ec3b..4735318 100644 (file)
@@ -259,7 +259,7 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
 {
        if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C))
                return &regmap_i2c;
-       else if (config->reg_bits == 8 &&
+       else if (config->val_bits == 8 && config->reg_bits == 8 &&
                 i2c_check_functionality(i2c->adapter,
                                         I2C_FUNC_SMBUS_I2C_BLOCK))
                return &regmap_i2c_smbus_i2c_block;
index 26f799e..ec26247 100644 (file)
@@ -268,13 +268,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        bool handled = false;
        u32 reg;
 
+       if (chip->handle_pre_irq)
+               chip->handle_pre_irq(chip->irq_drv_data);
+
        if (chip->runtime_pm) {
                ret = pm_runtime_get_sync(map->dev);
                if (ret < 0) {
                        dev_err(map->dev, "IRQ thread failed to resume: %d\n",
                                ret);
                        pm_runtime_put(map->dev);
-                       return IRQ_NONE;
+                       goto exit;
                }
        }
 
@@ -296,7 +299,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                if (ret != 0) {
                        dev_err(map->dev, "Failed to read IRQ status: %d\n",
                                ret);
-                       return IRQ_NONE;
+                       goto exit;
                }
 
                for (i = 0; i < data->chip->num_regs; i++) {
@@ -312,7 +315,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                break;
                        default:
                                BUG();
-                               return IRQ_NONE;
+                               goto exit;
                        }
                }
 
@@ -329,7 +332,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                                        ret);
                                if (chip->runtime_pm)
                                        pm_runtime_put(map->dev);
-                               return IRQ_NONE;
+                               goto exit;
                        }
                }
        }
@@ -365,6 +368,10 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        if (chip->runtime_pm)
                pm_runtime_put(map->dev);
 
+exit:
+       if (chip->handle_post_irq)
+               chip->handle_post_irq(chip->irq_drv_data);
+
        if (handled)
                return IRQ_HANDLED;
        else
index df2d2ef..51fa7d6 100644 (file)
@@ -1777,8 +1777,6 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
        size_t val_bytes = map->format.val_bytes;
        size_t total_size = val_bytes * val_count;
 
-       if (map->bus && !map->format.parse_inplace)
-               return -EINVAL;
        if (!IS_ALIGNED(reg, map->reg_stride))
                return -EINVAL;
 
@@ -1789,7 +1787,8 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
         *
         * The first if block is used for memory mapped io. It does not allow
         * val_bytes of 3 for example.
-        * The second one is used for busses which do not have this limitation
+        * The second one is for busses that do not provide raw I/O.
+        * The third one is used for busses which do not have these limitations
         * and can write arbitrary value lengths.
         */
        if (!map->bus) {
@@ -1825,6 +1824,32 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
                }
 out:
                map->unlock(map->lock_arg);
+       } else if (map->bus && !map->format.parse_inplace) {
+               const u8 *u8 = val;
+               const u16 *u16 = val;
+               const u32 *u32 = val;
+               unsigned int ival;
+
+               for (i = 0; i < val_count; i++) {
+                       switch (map->format.val_bytes) {
+                       case 4:
+                               ival = u32[i];
+                               break;
+                       case 2:
+                               ival = u16[i];
+                               break;
+                       case 1:
+                               ival = u8[i];
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+
+                       ret = regmap_write(map, reg + (i * map->reg_stride),
+                                          ival);
+                       if (ret)
+                               return ret;
+               }
        } else if (map->use_single_write ||
                   (map->max_raw_write && map->max_raw_write < total_size)) {
                int chunk_stride = map->reg_stride;
index 3dc08ce..2c12cc5 100644 (file)
@@ -95,6 +95,45 @@ struct reg_sequence {
 #define        regmap_fields_force_update_bits(field, id, mask, val) \
        regmap_fields_update_bits_base(field, id, mask, val, NULL, false, true)
 
+/**
+ * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs
+ * @map: Regmap to read from
+ * @addr: Address to poll
+ * @val: Unsigned integer variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in us (0
+ *            tight-loops).  Should be less than ~20ms since usleep_range
+ *            is used (see Documentation/timers/timers-howto.txt).
+ * @timeout_us: Timeout in us, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val. Must not be called
+ * from atomic context if sleep_us or timeout_us are used.
+ *
+ * This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
+ */
+#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_us) \
+({ \
+       ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
+       int ret; \
+       might_sleep_if(sleep_us); \
+       for (;;) { \
+               ret = regmap_read((map), (addr), &(val)); \
+               if (ret) \
+                       break; \
+               if (cond) \
+                       break; \
+               if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
+                       ret = regmap_read((map), (addr), &(val)); \
+                       break; \
+               } \
+               if (sleep_us) \
+                       usleep_range((sleep_us >> 2) + 1, sleep_us); \
+       } \
+       ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
 #ifdef CONFIG_REGMAP
 
 enum regmap_endian {
@@ -851,6 +890,12 @@ struct regmap_irq {
  * @num_type_reg:    Number of type registers.
  * @type_reg_stride: Stride to use for chips where type registers are not
  *                     contiguous.
+ * @handle_pre_irq:  Driver specific callback to handle interrupt from device
+ *                  before regmap_irq_handler process the interrupts.
+ * @handle_post_irq: Driver specific callback to handle interrupt from device
+ *                  after handling the interrupts in regmap_irq_handler().
+ * @irq_drv_data:    Driver specific IRQ data which is passed as parameter when
+ *                  driver specific pre/post interrupt handler is called.
  */
 struct regmap_irq_chip {
        const char *name;
@@ -877,6 +922,10 @@ struct regmap_irq_chip {
 
        int num_type_reg;
        unsigned int type_reg_stride;
+
+       int (*handle_pre_irq)(void *irq_drv_data);
+       int (*handle_post_irq)(void *irq_drv_data);
+       void *irq_drv_data;
 };
 
 struct regmap_irq_chip_data;