]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'regmap-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Jul 2017 18:50:07 +0000 (11:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 4 Jul 2017 18:50:07 +0000 (11:50 -0700)
Pull regmap updates from Mark Brown:
 "The usual small smattering of activity for regmap this time round:

   - Addition of support for the 1-Wire bus standard.

   - Options that allow support for more interrupt controllers with
     regmap-irq.

   - Only build LZO cache support if it's actually being used"

* tag 'regmap-v4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: irq: add chip option mask_writeonly
  regmap: irq: allow to register one cell interrupt controllers
  regmap: Fix typo in IS_ENABLED() check
  regmap: Add 1-Wire bus support
  regmap: make LZO cache optional

drivers/base/regmap/Kconfig
drivers/base/regmap/Makefile
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-w1.c [new file with mode: 0644]
include/linux/regmap.h

index db9d00c36a3e941e466665de2535399e2ee4a076..073c0b77e5b301f263fca13cd869cc20aef74d77 100644 (file)
@@ -3,10 +3,13 @@
 # subsystems should select the appropriate symbols.
 
 config REGMAP
-       default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+       default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+       select IRQ_DOMAIN if REGMAP_IRQ
+       bool
+
+config REGCACHE_COMPRESSED
        select LZO_COMPRESS
        select LZO_DECOMPRESS
-       select IRQ_DOMAIN if REGMAP_IRQ
        bool
 
 config REGMAP_AC97
@@ -24,6 +27,10 @@ config REGMAP_SPMI
        tristate
        depends on SPMI
 
+config REGMAP_W1
+       tristate
+       depends on W1
+
 config REGMAP_MMIO
        tristate
 
index 609e4c84f485b89ab0d219a3cfd06a2faf5a68ba..0cf4abc8fbf13f9128a006dd520f1bd344b62007 100644 (file)
@@ -2,7 +2,8 @@
 CFLAGS_regmap.o := -I$(src)
 
 obj-$(CONFIG_REGMAP) += regmap.o regcache.o
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
+obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o
+obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o
 obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
 obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
 obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
@@ -10,3 +11,4 @@ obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
 obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
 obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
 obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
+obj-$(CONFIG_REGMAP_W1) += regmap-w1.o
index b0a0dcf32fb7d05a0abdf725c158c47453652e34..773560348337fed60b363ee8f40e341fcc2044b7 100644 (file)
@@ -21,7 +21,9 @@
 
 static const struct regcache_ops *cache_types[] = {
        &regcache_rbtree_ops,
+#if IS_ENABLED(CONFIG_REGCACHE_COMPRESSED)
        &regcache_lzo_ops,
+#endif
        &regcache_flat_ops,
 };
 
index cd54189f2b1d4d18dd62172385848a75887bbc87..429ca8ed7e518087bc1ddaebd9f4c8393eb5179e 100644 (file)
@@ -60,6 +60,16 @@ static void regmap_irq_lock(struct irq_data *data)
        mutex_lock(&d->lock);
 }
 
+static int regmap_irq_update_bits(struct regmap_irq_chip_data *d,
+                                 unsigned int reg, unsigned int mask,
+                                 unsigned int val)
+{
+       if (d->chip->mask_writeonly)
+               return regmap_write_bits(d->map, reg, mask, val);
+       else
+               return regmap_update_bits(d->map, reg, mask, val);
+}
+
 static void regmap_irq_sync_unlock(struct irq_data *data)
 {
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
@@ -84,11 +94,11 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                reg = d->chip->mask_base +
                        (i * map->reg_stride * d->irq_reg_stride);
                if (d->chip->mask_invert) {
-                       ret = regmap_update_bits(d->map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                         d->mask_buf_def[i], ~d->mask_buf[i]);
                } else if (d->chip->unmask_base) {
                        /* set mask with mask_base register */
-                       ret = regmap_update_bits(d->map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                        d->mask_buf_def[i], ~d->mask_buf[i]);
                        if (ret < 0)
                                dev_err(d->map->dev,
@@ -97,12 +107,12 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                        unmask_offset = d->chip->unmask_base -
                                                        d->chip->mask_base;
                        /* clear mask with unmask_base register */
-                       ret = regmap_update_bits(d->map,
+                       ret = regmap_irq_update_bits(d,
                                        reg + unmask_offset,
                                        d->mask_buf_def[i],
                                        d->mask_buf[i]);
                } else {
-                       ret = regmap_update_bits(d->map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                         d->mask_buf_def[i], d->mask_buf[i]);
                }
                if (ret != 0)
@@ -113,11 +123,11 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                        (i * map->reg_stride * d->irq_reg_stride);
                if (d->wake_buf) {
                        if (d->chip->wake_invert)
-                               ret = regmap_update_bits(d->map, reg,
+                               ret = regmap_irq_update_bits(d, reg,
                                                         d->mask_buf_def[i],
                                                         ~d->wake_buf[i]);
                        else
-                               ret = regmap_update_bits(d->map, reg,
+                               ret = regmap_irq_update_bits(d, reg,
                                                         d->mask_buf_def[i],
                                                         d->wake_buf[i]);
                        if (ret != 0)
@@ -153,10 +163,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
                reg = d->chip->type_base +
                        (i * map->reg_stride * d->type_reg_stride);
                if (d->chip->type_invert)
-                       ret = regmap_update_bits(d->map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                d->type_buf_def[i], ~d->type_buf[i]);
                else
-                       ret = regmap_update_bits(d->map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                d->type_buf_def[i], d->type_buf[i]);
                if (ret != 0)
                        dev_err(d->map->dev, "Failed to sync type in %x\n",
@@ -394,7 +404,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
 
 static const struct irq_domain_ops regmap_domain_ops = {
        .map    = regmap_irq_map,
-       .xlate  = irq_domain_xlate_twocell,
+       .xlate  = irq_domain_xlate_onetwocell,
 };
 
 /**
@@ -519,17 +529,17 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                reg = chip->mask_base +
                        (i * map->reg_stride * d->irq_reg_stride);
                if (chip->mask_invert)
-                       ret = regmap_update_bits(map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                         d->mask_buf[i], ~d->mask_buf[i]);
                else if (d->chip->unmask_base) {
                        unmask_offset = d->chip->unmask_base -
                                        d->chip->mask_base;
-                       ret = regmap_update_bits(d->map,
+                       ret = regmap_irq_update_bits(d,
                                        reg + unmask_offset,
                                        d->mask_buf[i],
                                        d->mask_buf[i]);
                } else
-                       ret = regmap_update_bits(map, reg,
+                       ret = regmap_irq_update_bits(d, reg,
                                         d->mask_buf[i], d->mask_buf[i]);
                if (ret != 0) {
                        dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
@@ -575,11 +585,11 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                                (i * map->reg_stride * d->irq_reg_stride);
 
                        if (chip->wake_invert)
-                               ret = regmap_update_bits(map, reg,
+                               ret = regmap_irq_update_bits(d, reg,
                                                         d->mask_buf_def[i],
                                                         0);
                        else
-                               ret = regmap_update_bits(map, reg,
+                               ret = regmap_irq_update_bits(d, reg,
                                                         d->mask_buf_def[i],
                                                         d->wake_buf[i]);
                        if (ret != 0) {
@@ -603,10 +613,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        reg = chip->type_base +
                                (i * map->reg_stride * d->type_reg_stride);
                        if (chip->type_invert)
-                               ret = regmap_update_bits(map, reg,
+                               ret = regmap_irq_update_bits(d, reg,
                                        d->type_buf_def[i], 0xFF);
                        else
-                               ret = regmap_update_bits(map, reg,
+                               ret = regmap_irq_update_bits(d, reg,
                                        d->type_buf_def[i], 0x0);
                        if (ret != 0) {
                                dev_err(map->dev,
diff --git a/drivers/base/regmap/regmap-w1.c b/drivers/base/regmap/regmap-w1.c
new file mode 100644 (file)
index 0000000..5f04e7b
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Register map access API - W1 (1-Wire) support
+ *
+ * Copyright (C) 2017 OAO Radioavionica
+ * Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation
+ */
+
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include "../../w1/w1.h"
+
+#include "internal.h"
+
+#define W1_CMD_READ_DATA       0x69
+#define W1_CMD_WRITE_DATA      0x6C
+
+/*
+ * 1-Wire slaves registers with addess 8 bit and data 8 bit
+ */
+
+static int w1_reg_a8_v8_read(void *context, unsigned int reg, unsigned int *val)
+{
+       struct device *dev = context;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int ret = 0;
+
+       if (reg > 255)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->bus_mutex);
+       if (!w1_reset_select_slave(sl)) {
+               w1_write_8(sl->master, W1_CMD_READ_DATA);
+               w1_write_8(sl->master, reg);
+               *val = w1_read_8(sl->master);
+       } else {
+               ret = -ENODEV;
+       }
+       mutex_unlock(&sl->master->bus_mutex);
+
+       return ret;
+}
+
+static int w1_reg_a8_v8_write(void *context, unsigned int reg, unsigned int val)
+{
+       struct device *dev = context;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int ret = 0;
+
+       if (reg > 255)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->bus_mutex);
+       if (!w1_reset_select_slave(sl)) {
+               w1_write_8(sl->master, W1_CMD_WRITE_DATA);
+               w1_write_8(sl->master, reg);
+               w1_write_8(sl->master, val);
+       } else {
+               ret = -ENODEV;
+       }
+       mutex_unlock(&sl->master->bus_mutex);
+
+       return ret;
+}
+
+/*
+ * 1-Wire slaves registers with addess 8 bit and data 16 bit
+ */
+
+static int w1_reg_a8_v16_read(void *context, unsigned int reg,
+                               unsigned int *val)
+{
+       struct device *dev = context;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int ret = 0;
+
+       if (reg > 255)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->bus_mutex);
+       if (!w1_reset_select_slave(sl)) {
+               w1_write_8(sl->master, W1_CMD_READ_DATA);
+               w1_write_8(sl->master, reg);
+               *val = w1_read_8(sl->master);
+               *val |= w1_read_8(sl->master)<<8;
+       } else {
+               ret = -ENODEV;
+       }
+       mutex_unlock(&sl->master->bus_mutex);
+
+       return ret;
+}
+
+static int w1_reg_a8_v16_write(void *context, unsigned int reg,
+                               unsigned int val)
+{
+       struct device *dev = context;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int ret = 0;
+
+       if (reg > 255)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->bus_mutex);
+       if (!w1_reset_select_slave(sl)) {
+               w1_write_8(sl->master, W1_CMD_WRITE_DATA);
+               w1_write_8(sl->master, reg);
+               w1_write_8(sl->master, val & 0x00FF);
+               w1_write_8(sl->master, val>>8 & 0x00FF);
+       } else {
+               ret = -ENODEV;
+       }
+       mutex_unlock(&sl->master->bus_mutex);
+
+       return ret;
+}
+
+/*
+ * 1-Wire slaves registers with addess 16 bit and data 16 bit
+ */
+
+static int w1_reg_a16_v16_read(void *context, unsigned int reg,
+                               unsigned int *val)
+{
+       struct device *dev = context;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int ret = 0;
+
+       if (reg > 65535)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->bus_mutex);
+       if (!w1_reset_select_slave(sl)) {
+               w1_write_8(sl->master, W1_CMD_READ_DATA);
+               w1_write_8(sl->master, reg & 0x00FF);
+               w1_write_8(sl->master, reg>>8 & 0x00FF);
+               *val = w1_read_8(sl->master);
+               *val |= w1_read_8(sl->master)<<8;
+       } else {
+               ret = -ENODEV;
+       }
+       mutex_unlock(&sl->master->bus_mutex);
+
+       return ret;
+}
+
+static int w1_reg_a16_v16_write(void *context, unsigned int reg,
+                               unsigned int val)
+{
+       struct device *dev = context;
+       struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+       int ret = 0;
+
+       if (reg > 65535)
+               return -EINVAL;
+
+       mutex_lock(&sl->master->bus_mutex);
+       if (!w1_reset_select_slave(sl)) {
+               w1_write_8(sl->master, W1_CMD_WRITE_DATA);
+               w1_write_8(sl->master, reg & 0x00FF);
+               w1_write_8(sl->master, reg>>8 & 0x00FF);
+               w1_write_8(sl->master, val & 0x00FF);
+               w1_write_8(sl->master, val>>8 & 0x00FF);
+       } else {
+               ret = -ENODEV;
+       }
+       mutex_unlock(&sl->master->bus_mutex);
+
+       return ret;
+}
+
+/*
+ * Various types of supported bus addressing
+ */
+
+static struct regmap_bus regmap_w1_bus_a8_v8 = {
+       .reg_read = w1_reg_a8_v8_read,
+       .reg_write = w1_reg_a8_v8_write,
+};
+
+static struct regmap_bus regmap_w1_bus_a8_v16 = {
+       .reg_read = w1_reg_a8_v16_read,
+       .reg_write = w1_reg_a8_v16_write,
+};
+
+static struct regmap_bus regmap_w1_bus_a16_v16 = {
+       .reg_read = w1_reg_a16_v16_read,
+       .reg_write = w1_reg_a16_v16_write,
+};
+
+static const struct regmap_bus *regmap_get_w1_bus(struct device *w1_dev,
+                                       const struct regmap_config *config)
+{
+       if (config->reg_bits == 8 && config->val_bits == 8)
+               return &regmap_w1_bus_a8_v8;
+
+       if (config->reg_bits == 8 && config->val_bits == 16)
+               return &regmap_w1_bus_a8_v16;
+
+       if (config->reg_bits == 16 && config->val_bits == 16)
+               return &regmap_w1_bus_a16_v16;
+
+       return ERR_PTR(-ENOTSUPP);
+}
+
+struct regmap *__regmap_init_w1(struct device *w1_dev,
+                                const struct regmap_config *config,
+                                struct lock_class_key *lock_key,
+                                const char *lock_name)
+{
+
+       const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config);
+
+       if (IS_ERR(bus))
+               return ERR_CAST(bus);
+
+       return __regmap_init(w1_dev, bus, w1_dev, config,
+                        lock_key, lock_name);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(__regmap_init_w1);
+
+struct regmap *__devm_regmap_init_w1(struct device *w1_dev,
+                                const struct regmap_config *config,
+                                struct lock_class_key *lock_key,
+                                const char *lock_name)
+{
+
+       const struct regmap_bus *bus = regmap_get_w1_bus(w1_dev, config);
+
+       if (IS_ERR(bus))
+               return ERR_CAST(bus);
+
+       return __devm_regmap_init(w1_dev, bus, w1_dev, config,
+                                lock_key, lock_name);
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_w1);
+
+MODULE_LICENSE("GPL");
index e88649225a6073fea86bc77d99bdf3109fe7838d..978abfbac61783091046d63dbe23aedd2ad82b3c 100644 (file)
@@ -461,6 +461,10 @@ struct regmap *__regmap_init_spmi_ext(struct spmi_device *dev,
                                      const struct regmap_config *config,
                                      struct lock_class_key *lock_key,
                                      const char *lock_name);
+struct regmap *__regmap_init_w1(struct device *w1_dev,
+                                const struct regmap_config *config,
+                                struct lock_class_key *lock_key,
+                                const char *lock_name);
 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
                                      void __iomem *regs,
                                      const struct regmap_config *config,
@@ -493,6 +497,10 @@ struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *dev,
                                           const struct regmap_config *config,
                                           struct lock_class_key *lock_key,
                                           const char *lock_name);
+struct regmap *__devm_regmap_init_w1(struct device *w1_dev,
+                                     const struct regmap_config *config,
+                                     struct lock_class_key *lock_key,
+                                     const char *lock_name);
 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
                                           const char *clk_id,
                                           void __iomem *regs,
@@ -596,6 +604,19 @@ int regmap_attach_dev(struct device *dev, struct regmap *map,
        __regmap_lockdep_wrapper(__regmap_init_spmi_ext, #config,       \
                                dev, config)
 
+/**
+ * regmap_init_w1() - Initialise register map
+ *
+ * @w1_dev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+#define regmap_init_w1(w1_dev, config)                                 \
+       __regmap_lockdep_wrapper(__regmap_init_w1, #config,             \
+                               w1_dev, config)
+
 /**
  * regmap_init_mmio_clk() - Initialise register map with register clock
  *
@@ -711,6 +732,19 @@ bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
        __regmap_lockdep_wrapper(__devm_regmap_init_spmi_ext, #config,  \
                                dev, config)
 
+/**
+ * devm_regmap_init_w1() - Initialise managed register map
+ *
+ * @w1_dev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap.  The regmap will be automatically freed by the
+ * device management code.
+ */
+#define devm_regmap_init_w1(w1_dev, config)                            \
+       __regmap_lockdep_wrapper(__devm_regmap_init_w1, #config,        \
+                               w1_dev, config)
 /**
  * devm_regmap_init_mmio_clk() - Initialise managed register map with clock
  *
@@ -884,6 +918,7 @@ struct regmap_irq {
  *
  * @status_base: Base status register address.
  * @mask_base:   Base mask register address.
+ * @mask_writeonly: Base mask register is write only.
  * @unmask_base:  Base unmask register address. for chips who have
  *                separate mask and unmask registers
  * @ack_base:    Base ack address. If zero then the chip is clear on read.
@@ -927,6 +962,7 @@ struct regmap_irq_chip {
        unsigned int wake_base;
        unsigned int type_base;
        unsigned int irq_reg_stride;
+       bool mask_writeonly:1;
        bool init_ack_masked:1;
        bool mask_invert:1;
        bool use_ack:1;